# ALL_FMTS
set(ALL_FMTS ${MINIMAL_FMTS}
- bcr.cc
brauniger_iq.cc
delgpl.cc
destinator.cc
html.cc
humminbird.cc
igc.cc
- ignrando.cc
- igo8.cc
- ik3d.cc
itracku.cc
- lmx.cc
lowranceusr.cc
- mapasia.cc
mapbar_track.cc
- mapfactor.cc
- mmo.cc
- mtk_locus.cc
mtk_logger.cc
- mynav.cc
navilink.cc
navitel.cc
osm.cc
lowranceusr.h
magellan.h
mapbar_track.h
- mapfactor.h
- mynav.h
navilink.h
nmea.h
osm.h
# ALL_FMTS
ALL_FMTS = $$MINIMAL_FMTS \
- bcr.cc \
brauniger_iq.cc \
delgpl.cc \
destinator.cc \
html.cc \
humminbird.cc \
igc.cc \
- ignrando.cc \
- igo8.cc \
- ik3d.cc \
itracku.cc \
- lmx.cc \
lowranceusr.cc \
- mapasia.cc \
mapbar_track.cc \
- mapfactor.cc \
- mmo.cc \
- mtk_locus.cc \
mtk_logger.cc \
- mynav.cc \
navilink.cc \
navitel.cc \
osm.cc \
lowranceusr.h \
magellan.h \
mapbar_track.h \
- mapfactor.h \
- mynav.h \
navilink.h \
nmea.h \
osm.h \
+++ /dev/null
-/*
-
- Support for Motorrad Routenplaner (Map&Guide) .bcr files.
-
- Copyright (C) 2005-2007 Olaf Klein, o.b.klein@gpsbabel.org
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-/*
- 2006/01/22: reader simplified with inifile library
- 2007/01/30: new option prefer_shortnames
- don't check global_opts.objective
- 2007/04&14: new handling of DESCRIPTION lines
-*/
-
-#include <cmath> // for M_PI, atan, exp, log, tan
-#include <cstdio> // for printf, snprintf, sscanf
-#include <cstdlib> // for atof, atoi
-
-#include <QString> // for QString, operator+
-#include <Qt> // for CaseInsensitive
-#include <QtGlobal> // for foreach
-
-#include "defs.h"
-#include "csv_util.h" // for csv_stringclean
-#include "garmin_tables.h" // for gt_find_desc_from_icon_number, gt_find_icon_number_from_desc, MAPSOURCE
-#include "gbfile.h" // for gbfprintf, gbfclose, gbfopen, gbfile
-#include "inifile.h" // for inifile_readstr, inifile_done, inifile_init, inifile_t
-
-
-#define MYNAME "bcr"
-
-#undef BCR_DEBUG
-
-#define R_EARTH 6371000 /* radius of our big blue ball */
-#define BCR_DEF_ICON "Standort"
-#define BCR_DEF_MPS_ICON "Waypoint"
-#define BCR_UNKNOWN /*(double) */ 999999999
-
-/*
- 6371014 would be a better value when converting to f.e. to mapsoure,
- but this seems to be used by Map&Guide when exporting to XML.
-*/
-
-static gbfile* fout;
-static int curr_rte_num, target_rte_num;
-static double radius;
-static inifile_t* ini;
-
-/* placeholders for options */
-
-static char* rtenum_opt;
-static char* rtename_opt;
-static char* radius_opt;
-static char* prefer_shortnames_opt;
-
-static
-QVector<arglist_t> bcr_args = {
- {
- "index", &rtenum_opt, "Index of route to write (if more than one in source)",
- nullptr, ARGTYPE_INT, "1", nullptr, nullptr
- },
- {
- "name", &rtename_opt, "New name for the route",
- nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr
- },
- {
- "radius", &radius_opt, "Radius of our big earth (default 6371000 meters)", "6371000",
- ARGTYPE_FLOAT, ARG_NOMINMAX, nullptr
- },
- {
- "prefer_shortnames", &prefer_shortnames_opt, "Use shortname instead of description",
- nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
- },
-};
-
-struct bcr_icon_mapping_t {
- const char* bcr_name;
- const char* mps_name;
- const char* symbol_DE;
- bool warned;
-};
-
-static
-bcr_icon_mapping_t bcr_icon_mapping[] = {
- { BCR_DEF_ICON, BCR_DEF_MPS_ICON, BCR_DEF_ICON, false },
- { "", BCR_DEF_MPS_ICON, "Eigene Adressen", false },
- { "AdrMon alpen", "Summit", "Pass-Strassen", false },
- { "AdrMon bauern", nullptr, "Bauern- und Biohoefe", false },
- { "AdrMon cmpngs", "Campground", "Campingplaetzte", false },
- { "AdrMon p_aeu", "Scenic Area", "Sehenswertes", false },
- { "AdrMon p_beu", "Gas Station", "Tanken", false },
- { "AdrMon p_deu", "Parking Area", "Parken", false },
- { "AdrMon p_feu", "Restaurant", "Gastro", false },
- { "AdrMon p_geu", "Museum", "Freizeit", false },
- { "AdrMon p_heu", "Gas Station", "Tankstellen", false },
- { "AdrMon p_keu", nullptr, "Faehrverbindungen", false },
- { "AdrMon p_leu", nullptr, "Grenzuebergaenge", false },
- { "AdrMon p_teu", nullptr, "Wein- und Sektgueter", false },
- { "AdrMon RUINEN", "Ghost Town", "Burgen und Schloesser", false },
- { "AdrMon NFHAUS", "Residence", "Naturfreundehaeuser", false },
- { "AdrMon racing", "Bike Trail", "Rennstrecken", false },
- { "AdrMon TNKRST", "Bar", "Tankraststaetten", false },
- { "AdrMon tpclub", "Contact, Biker", "Motorrad-Clubs", false },
- { "AdrMon tpequ", nullptr, "Motorrad-Equipment", false },
- { "AdrMon tphot", "Hotel", "Motorrad-Hotels", false },
- { "AdrMon tpmh", nullptr, "Motorradhaendler", false },
- { "AdrMon tpss", "Restricted Area", "Sperrungen", false },
- { "AdrMon tpsw", "Scenic Area", "Sehenswertes", false },
- { "AdrMon tptref", nullptr, "Treffpunkte", false },
- { "AdrMon VORTE", "Information", "Ortsinformationen", false },
- { "AdrMon WEBCAM", nullptr, "WebCam-Standorte", false },
- { "AdrMon youthh", nullptr, "Jugendherbergen", false },
- { "Town", "City (Small)", "Orte", false },
- { nullptr, nullptr, nullptr, false }
-};
-
-static void
-bcr_handle_icon_str(const char* str, Waypoint* wpt)
-{
- wpt->icon_descr = BCR_DEF_MPS_ICON;
-
- for (bcr_icon_mapping_t* m = bcr_icon_mapping; (m->bcr_name); m++) {
- if (case_ignore_strcmp(str, m->bcr_name) == 0) {
- if (m->symbol_DE == nullptr) {
- if (! m->warned) {
- m->warned = true;
- warning(MYNAME ": Unknown icon \"%s\" found. Please report.\n", str);
- }
- return;
- }
- wpt->description = m->symbol_DE;
- if (m->mps_name != nullptr) {
- int nr = gt_find_icon_number_from_desc(m->mps_name, MAPSOURCE);
- wpt->icon_descr = gt_find_desc_from_icon_number(nr, MAPSOURCE);
- }
- return;
- }
- }
-}
-
-static const char*
-get_bcr_icon_from_icon_descr(const QString& icon_descr)
-{
- const char* result = BCR_DEF_ICON;
-
- if (!icon_descr.isNull()) {
- for (bcr_icon_mapping_t* m = bcr_icon_mapping; (m->bcr_name); m++) {
- if (! m->mps_name) {
- continue;
- }
- if (icon_descr.compare(m->mps_name, Qt::CaseInsensitive) == 0) {
- result = m->bcr_name;
- break;
- }
- }
- }
- return result;
-}
-
-static void
-bcr_init_radius()
-{
- if (radius_opt != nullptr) { /* preinitialize the earth radius */
- radius = atof(radius_opt);
- if (radius <= 0) {
- fatal(MYNAME ": Sorry, the radius should be greater than zero!\n");
- }
- } else {
- radius = (double)R_EARTH;
- }
-
- if (global_opts.verbose_status > 0) {
- printf(MYNAME ": We calculate with radius %f meters.\n", radius);
- }
-}
-
-static void
-bcr_rd_init(const QString& fname)
-{
- ini = inifile_init(fname, MYNAME);
- bcr_init_radius();
-}
-
-static void
-bcr_rd_deinit()
-{
- inifile_done(ini);
-}
-
-/* ------------------------------------------------------------*/
-
-static void
-bcr_create_waypts_from_route(route_head* route)
-{
- foreach (const Waypoint* wpt, route->waypoint_list) {
- waypt_add(new Waypoint(*wpt));
- }
-}
-
-static void
-bcr_wgs84_to_mercator(const double lat, const double lon, int* north, int* east)
-{
- double N = log(tan(lat * M_PI / 360 + M_PI / 4)) * radius;
- double E = lon * radius * M_PI / 180.0;
-
- if (lat > 0) {
- N += 0.500000000001; /* we go from double to integer */
- } else {
- N -= 0.500000000001; /* it's time to round a little bit */
- }
- if (lon > 0) {
- E += 0.500000000001;
- } else {
- E -= 0.500000000001;
- }
-
- *north = N;
- *east = E;
-}
-
-static void
-bcr_mercator_to_wgs84(const int north, const int east, double* lat, double* lon)
-{
- *lat = 2 * (atan(exp(north / radius)) - M_PI / 4) / M_PI * 180.0;
- *lon = (double)east * 180.0 / (radius * M_PI);
-}
-
-/* ------------------------------------------------------------- */
-
-static void
-bcr_data_read()
-{
- auto* route = new route_head;
- route_add_head(route);
-
- QString routename = inifile_readstr(ini, "client", "routename");
- if (!routename.isNull()) {
- route->rte_name = routename;
- }
-
- for (int index = 1; ; index++) {
- char station[32];
- QString str;
- int mlat, mlon; /* mercator data */
-
- snprintf(station, sizeof(station), "STATION%d", index);
- str = inifile_readstr(ini, "coordinates", station);
- if (str.isNull()) {
- break;
- }
-
- if (2 != sscanf(CSTR(str), "%d,%d", &mlon, &mlat)) {
- fatal(MYNAME ": structure error at %s (Coordinates)!\n", station);
- }
-
- auto* wpt = new Waypoint;
-
- wpt->shortname = station;
- bcr_mercator_to_wgs84(mlat, mlon, &wpt->latitude, &wpt->longitude);
-
- str = inifile_readstr(ini, "client", station);
- if (!str.isNull()) {
- int cx = str.indexOf(',');
- if (cx < 0) {
- fatal(MYNAME ": structure error at %s (Client)!\n", station);
- }
- bcr_handle_icon_str(CSTR(str.left(cx)), wpt);
- }
-
- str = inifile_readstr(ini, "description", station);
- if (!str.isNull()) {
- QString note = str.section(',', 0, 0);
- if (!note.isEmpty()) {
- wpt->notes = note;
- }
- QString shortname = str.section(',', 1, 1);
- if (!shortname.isEmpty()) {
- wpt->shortname = shortname;
- }
- }
-
- route_add_wpt(route, wpt);
- }
-
- /* remove empty route */
- if (route->rte_waypt_ct() == 0) {
- route_del_head(route);
- } else {
- bcr_create_waypts_from_route(route);
- }
-}
-
-/* %%% bcr write support %%% ----------------------------------- */
-
-static void
-bcr_wr_init(const QString& fname)
-{
- fout = gbfopen(fname, "wb", MYNAME);
- bcr_init_radius();
-}
-
-static void
-bcr_wr_deinit()
-{
- gbfclose(fout);
-}
-
-static void bcr_write_line(gbfile* fileout, const QString& key,
- const int* index, const QString& value)
-{
- if (value.isEmpty()) { // Windows. Add CR/LF on output.
- gbfprintf(fileout, "%s\r\n", CSTR(key));
- } else {
- char* tmp = (value != nullptr) ? xstrdup(value) : xstrdup("");
- if (index != nullptr) {
- gbfprintf(fileout, "%s%d=%s\r\n", CSTR(key), *index, tmp);
- } else {
- gbfprintf(fileout, "%s=%s\r\n", CSTR(key), tmp);
- }
- xfree(tmp);
- }
-}
-
-static void
-bcr_route_header(const route_head* route)
-{
- int north, east, nmax, emin;
-
- curr_rte_num++;
- if (curr_rte_num != target_rte_num) {
- return;
- }
-
- bcr_write_line(fout, "[CLIENT]", nullptr, nullptr); /* client section */
- bcr_write_line(fout, "REQUEST", nullptr, "TRUE");
-
- QString sout = route->rte_name;
- if (rtename_opt != nullptr) {
- sout = rtename_opt;
- }
- if (sout != nullptr) {
- bcr_write_line(fout, "ROUTENAME", nullptr, sout);
- } else {
- bcr_write_line(fout, "ROUTENAME", nullptr, "Route");
- }
-
- bcr_write_line(fout, "DESCRIPTIONLINES", nullptr, "0");
-
- int i = 0;
- foreach (const Waypoint* wpt, route->waypoint_list) {
-
- i++;
-
- const char* icon = get_bcr_icon_from_icon_descr(wpt->icon_descr);
-
- sout = QString("%1,%2").arg(icon).arg(BCR_UNKNOWN,10);
- bcr_write_line(fout, "STATION", &i, sout);
- }
-
- bcr_write_line(fout, "[COORDINATES]", nullptr, nullptr); /* coords section */
-
- int nmin = emin = (1<<30);
- int emax = nmax = -nmin;
-
- i = 0;
- foreach (const Waypoint* wpt, route->waypoint_list) {
- i++;
-
- bcr_wgs84_to_mercator(wpt->latitude, wpt->longitude, &north, &east);
-
- if (north > nmax) {
- nmax = north;
- }
- if (east > emax) {
- emax = east;
- }
- if (north < nmin) {
- nmin = north;
- }
- if (east < emin) {
- emin = east;
- }
-
- sout = QString::number(east) + "," + QString::number(north);
- bcr_write_line(fout, "STATION", &i, sout);
- }
-
- bcr_write_line(fout, "[DESCRIPTION]", nullptr, nullptr); /* descr. section */
-
- i = 0;
- foreach (const Waypoint* wpt, route->waypoint_list) {
- QString s2;
-
- i++;
- QString s1 = wpt->notes;
- if (s1.isEmpty()) {
- s1 = wpt->description;
- }
-
- if (prefer_shortnames_opt || (s1.isEmpty())) {
- s2 = s1;
- s1 = wpt->shortname;
- } else {
- s2 = wpt->shortname;
- }
-
- if (s1.isEmpty()) {
- s1 = QString();
- } else {
- s1 = csv_stringclean(s1, ",\t\r\n");
- }
- if (s2.isEmpty()) {
- s2 = QString();
- } else {
- s2 = csv_stringclean(s2, ",\t\r\n");
- }
-
- if (sout.isEmpty()) {
- sout = QString("%1,%2,@,0").arg(s1, s1);
- } else {
- sout = QString("%1,%2,@,0").arg(s1, s2);
- }
-
- bcr_write_line(fout, "STATION", &i, sout);
- }
-
- bcr_write_line(fout, "[ROUTE]", nullptr, nullptr); /* route section */
-
- sout = QString::number(emin) + "," +
- QString::number(nmax) + "," +
- QString::number(emax) + "," +
- QString::number(nmin);
- bcr_write_line(fout, "ROUTERECT", nullptr, sout);
-}
-
-static void
-bcr_data_write()
-{
- target_rte_num = 1;
-
- if (rtenum_opt != nullptr) {
- target_rte_num = atoi(rtenum_opt);
- if (((unsigned)target_rte_num > route_count()) || (target_rte_num < 1))
- fatal(MYNAME ": invalid route number %d (1..%d))!\n",
- target_rte_num, route_count());
- }
- curr_rte_num = 0;
- route_disp_all(bcr_route_header, nullptr, nullptr);
-}
-
-ff_vecs_t bcr_vecs = {
- ff_type_file,
- { ff_cap_none, ff_cap_none, (ff_cap)(ff_cap_read | ff_cap_write)},
- bcr_rd_init,
- bcr_wr_init,
- bcr_rd_deinit,
- bcr_wr_deinit,
- bcr_data_read,
- bcr_data_write,
- nullptr,
- &bcr_args,
- CET_CHARSET_MS_ANSI, 0, /* CET-REVIEW */
- NULL_POS_OPS
-};
--- /dev/null
+/*
+
+ Support for Motorrad Routenplaner (Map&Guide) .bcr files.
+
+ Copyright (C) 2005-2007 Olaf Klein, o.b.klein@gpsbabel.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/*
+ 2006/01/22: reader simplified with inifile library
+ 2007/01/30: new option prefer_shortnames
+ don't check global_opts.objective
+ 2007/04&14: new handling of DESCRIPTION lines
+*/
+
+#include <cmath> // for M_PI, atan, exp, log, tan
+#include <cstdio> // for printf, snprintf, sscanf
+#include <cstdlib> // for atof, atoi
+
+#include <QString> // for QString, operator+
+#include <Qt> // for CaseInsensitive
+#include <QtGlobal> // for foreach
+
+#include "defs.h"
+#include "csv_util.h" // for csv_stringclean
+#include "garmin_tables.h" // for gt_find_desc_from_icon_number, gt_find_icon_number_from_desc, MAPSOURCE
+#include "gbfile.h" // for gbfprintf, gbfclose, gbfopen, gbfile
+#include "inifile.h" // for inifile_readstr, inifile_done, inifile_init, inifile_t
+
+
+#define MYNAME "bcr"
+
+#undef BCR_DEBUG
+
+#define R_EARTH 6371000 /* radius of our big blue ball */
+#define BCR_DEF_ICON "Standort"
+#define BCR_DEF_MPS_ICON "Waypoint"
+#define BCR_UNKNOWN /*(double) */ 999999999
+
+/*
+ 6371014 would be a better value when converting to f.e. to mapsoure,
+ but this seems to be used by Map&Guide when exporting to XML.
+*/
+
+static gbfile* fout;
+static int curr_rte_num, target_rte_num;
+static double radius;
+static inifile_t* ini;
+
+/* placeholders for options */
+
+static char* rtenum_opt;
+static char* rtename_opt;
+static char* radius_opt;
+static char* prefer_shortnames_opt;
+
+static
+QVector<arglist_t> bcr_args = {
+ {
+ "index", &rtenum_opt, "Index of route to write (if more than one in source)",
+ nullptr, ARGTYPE_INT, "1", nullptr, nullptr
+ },
+ {
+ "name", &rtename_opt, "New name for the route",
+ nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr
+ },
+ {
+ "radius", &radius_opt, "Radius of our big earth (default 6371000 meters)", "6371000",
+ ARGTYPE_FLOAT, ARG_NOMINMAX, nullptr
+ },
+ {
+ "prefer_shortnames", &prefer_shortnames_opt, "Use shortname instead of description",
+ nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+ },
+};
+
+struct bcr_icon_mapping_t {
+ const char* bcr_name;
+ const char* mps_name;
+ const char* symbol_DE;
+ bool warned;
+};
+
+static
+bcr_icon_mapping_t bcr_icon_mapping[] = {
+ { BCR_DEF_ICON, BCR_DEF_MPS_ICON, BCR_DEF_ICON, false },
+ { "", BCR_DEF_MPS_ICON, "Eigene Adressen", false },
+ { "AdrMon alpen", "Summit", "Pass-Strassen", false },
+ { "AdrMon bauern", nullptr, "Bauern- und Biohoefe", false },
+ { "AdrMon cmpngs", "Campground", "Campingplaetzte", false },
+ { "AdrMon p_aeu", "Scenic Area", "Sehenswertes", false },
+ { "AdrMon p_beu", "Gas Station", "Tanken", false },
+ { "AdrMon p_deu", "Parking Area", "Parken", false },
+ { "AdrMon p_feu", "Restaurant", "Gastro", false },
+ { "AdrMon p_geu", "Museum", "Freizeit", false },
+ { "AdrMon p_heu", "Gas Station", "Tankstellen", false },
+ { "AdrMon p_keu", nullptr, "Faehrverbindungen", false },
+ { "AdrMon p_leu", nullptr, "Grenzuebergaenge", false },
+ { "AdrMon p_teu", nullptr, "Wein- und Sektgueter", false },
+ { "AdrMon RUINEN", "Ghost Town", "Burgen und Schloesser", false },
+ { "AdrMon NFHAUS", "Residence", "Naturfreundehaeuser", false },
+ { "AdrMon racing", "Bike Trail", "Rennstrecken", false },
+ { "AdrMon TNKRST", "Bar", "Tankraststaetten", false },
+ { "AdrMon tpclub", "Contact, Biker", "Motorrad-Clubs", false },
+ { "AdrMon tpequ", nullptr, "Motorrad-Equipment", false },
+ { "AdrMon tphot", "Hotel", "Motorrad-Hotels", false },
+ { "AdrMon tpmh", nullptr, "Motorradhaendler", false },
+ { "AdrMon tpss", "Restricted Area", "Sperrungen", false },
+ { "AdrMon tpsw", "Scenic Area", "Sehenswertes", false },
+ { "AdrMon tptref", nullptr, "Treffpunkte", false },
+ { "AdrMon VORTE", "Information", "Ortsinformationen", false },
+ { "AdrMon WEBCAM", nullptr, "WebCam-Standorte", false },
+ { "AdrMon youthh", nullptr, "Jugendherbergen", false },
+ { "Town", "City (Small)", "Orte", false },
+ { nullptr, nullptr, nullptr, false }
+};
+
+static void
+bcr_handle_icon_str(const char* str, Waypoint* wpt)
+{
+ wpt->icon_descr = BCR_DEF_MPS_ICON;
+
+ for (bcr_icon_mapping_t* m = bcr_icon_mapping; (m->bcr_name); m++) {
+ if (case_ignore_strcmp(str, m->bcr_name) == 0) {
+ if (m->symbol_DE == nullptr) {
+ if (! m->warned) {
+ m->warned = true;
+ warning(MYNAME ": Unknown icon \"%s\" found. Please report.\n", str);
+ }
+ return;
+ }
+ wpt->description = m->symbol_DE;
+ if (m->mps_name != nullptr) {
+ int nr = gt_find_icon_number_from_desc(m->mps_name, MAPSOURCE);
+ wpt->icon_descr = gt_find_desc_from_icon_number(nr, MAPSOURCE);
+ }
+ return;
+ }
+ }
+}
+
+static const char*
+get_bcr_icon_from_icon_descr(const QString& icon_descr)
+{
+ const char* result = BCR_DEF_ICON;
+
+ if (!icon_descr.isNull()) {
+ for (bcr_icon_mapping_t* m = bcr_icon_mapping; (m->bcr_name); m++) {
+ if (! m->mps_name) {
+ continue;
+ }
+ if (icon_descr.compare(m->mps_name, Qt::CaseInsensitive) == 0) {
+ result = m->bcr_name;
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+static void
+bcr_init_radius()
+{
+ if (radius_opt != nullptr) { /* preinitialize the earth radius */
+ radius = atof(radius_opt);
+ if (radius <= 0) {
+ fatal(MYNAME ": Sorry, the radius should be greater than zero!\n");
+ }
+ } else {
+ radius = (double)R_EARTH;
+ }
+
+ if (global_opts.verbose_status > 0) {
+ printf(MYNAME ": We calculate with radius %f meters.\n", radius);
+ }
+}
+
+static void
+bcr_rd_init(const QString& fname)
+{
+ ini = inifile_init(fname, MYNAME);
+ bcr_init_radius();
+}
+
+static void
+bcr_rd_deinit()
+{
+ inifile_done(ini);
+}
+
+/* ------------------------------------------------------------*/
+
+static void
+bcr_create_waypts_from_route(route_head* route)
+{
+ foreach (const Waypoint* wpt, route->waypoint_list) {
+ waypt_add(new Waypoint(*wpt));
+ }
+}
+
+static void
+bcr_wgs84_to_mercator(const double lat, const double lon, int* north, int* east)
+{
+ double N = log(tan(lat * M_PI / 360 + M_PI / 4)) * radius;
+ double E = lon * radius * M_PI / 180.0;
+
+ if (lat > 0) {
+ N += 0.500000000001; /* we go from double to integer */
+ } else {
+ N -= 0.500000000001; /* it's time to round a little bit */
+ }
+ if (lon > 0) {
+ E += 0.500000000001;
+ } else {
+ E -= 0.500000000001;
+ }
+
+ *north = N;
+ *east = E;
+}
+
+static void
+bcr_mercator_to_wgs84(const int north, const int east, double* lat, double* lon)
+{
+ *lat = 2 * (atan(exp(north / radius)) - M_PI / 4) / M_PI * 180.0;
+ *lon = (double)east * 180.0 / (radius * M_PI);
+}
+
+/* ------------------------------------------------------------- */
+
+static void
+bcr_data_read()
+{
+ auto* route = new route_head;
+ route_add_head(route);
+
+ QString routename = inifile_readstr(ini, "client", "routename");
+ if (!routename.isNull()) {
+ route->rte_name = routename;
+ }
+
+ for (int index = 1; ; index++) {
+ char station[32];
+ QString str;
+ int mlat, mlon; /* mercator data */
+
+ snprintf(station, sizeof(station), "STATION%d", index);
+ str = inifile_readstr(ini, "coordinates", station);
+ if (str.isNull()) {
+ break;
+ }
+
+ if (2 != sscanf(CSTR(str), "%d,%d", &mlon, &mlat)) {
+ fatal(MYNAME ": structure error at %s (Coordinates)!\n", station);
+ }
+
+ auto* wpt = new Waypoint;
+
+ wpt->shortname = station;
+ bcr_mercator_to_wgs84(mlat, mlon, &wpt->latitude, &wpt->longitude);
+
+ str = inifile_readstr(ini, "client", station);
+ if (!str.isNull()) {
+ int cx = str.indexOf(',');
+ if (cx < 0) {
+ fatal(MYNAME ": structure error at %s (Client)!\n", station);
+ }
+ bcr_handle_icon_str(CSTR(str.left(cx)), wpt);
+ }
+
+ str = inifile_readstr(ini, "description", station);
+ if (!str.isNull()) {
+ QString note = str.section(',', 0, 0);
+ if (!note.isEmpty()) {
+ wpt->notes = note;
+ }
+ QString shortname = str.section(',', 1, 1);
+ if (!shortname.isEmpty()) {
+ wpt->shortname = shortname;
+ }
+ }
+
+ route_add_wpt(route, wpt);
+ }
+
+ /* remove empty route */
+ if (route->rte_waypt_ct() == 0) {
+ route_del_head(route);
+ } else {
+ bcr_create_waypts_from_route(route);
+ }
+}
+
+/* %%% bcr write support %%% ----------------------------------- */
+
+static void
+bcr_wr_init(const QString& fname)
+{
+ fout = gbfopen(fname, "wb", MYNAME);
+ bcr_init_radius();
+}
+
+static void
+bcr_wr_deinit()
+{
+ gbfclose(fout);
+}
+
+static void bcr_write_line(gbfile* fileout, const QString& key,
+ const int* index, const QString& value)
+{
+ if (value.isEmpty()) { // Windows. Add CR/LF on output.
+ gbfprintf(fileout, "%s\r\n", CSTR(key));
+ } else {
+ char* tmp = (value != nullptr) ? xstrdup(value) : xstrdup("");
+ if (index != nullptr) {
+ gbfprintf(fileout, "%s%d=%s\r\n", CSTR(key), *index, tmp);
+ } else {
+ gbfprintf(fileout, "%s=%s\r\n", CSTR(key), tmp);
+ }
+ xfree(tmp);
+ }
+}
+
+static void
+bcr_route_header(const route_head* route)
+{
+ int north, east, nmax, emin;
+
+ curr_rte_num++;
+ if (curr_rte_num != target_rte_num) {
+ return;
+ }
+
+ bcr_write_line(fout, "[CLIENT]", nullptr, nullptr); /* client section */
+ bcr_write_line(fout, "REQUEST", nullptr, "TRUE");
+
+ QString sout = route->rte_name;
+ if (rtename_opt != nullptr) {
+ sout = rtename_opt;
+ }
+ if (sout != nullptr) {
+ bcr_write_line(fout, "ROUTENAME", nullptr, sout);
+ } else {
+ bcr_write_line(fout, "ROUTENAME", nullptr, "Route");
+ }
+
+ bcr_write_line(fout, "DESCRIPTIONLINES", nullptr, "0");
+
+ int i = 0;
+ foreach (const Waypoint* wpt, route->waypoint_list) {
+
+ i++;
+
+ const char* icon = get_bcr_icon_from_icon_descr(wpt->icon_descr);
+
+ sout = QString("%1,%2").arg(icon).arg(BCR_UNKNOWN,10);
+ bcr_write_line(fout, "STATION", &i, sout);
+ }
+
+ bcr_write_line(fout, "[COORDINATES]", nullptr, nullptr); /* coords section */
+
+ int nmin = emin = (1<<30);
+ int emax = nmax = -nmin;
+
+ i = 0;
+ foreach (const Waypoint* wpt, route->waypoint_list) {
+ i++;
+
+ bcr_wgs84_to_mercator(wpt->latitude, wpt->longitude, &north, &east);
+
+ if (north > nmax) {
+ nmax = north;
+ }
+ if (east > emax) {
+ emax = east;
+ }
+ if (north < nmin) {
+ nmin = north;
+ }
+ if (east < emin) {
+ emin = east;
+ }
+
+ sout = QString::number(east) + "," + QString::number(north);
+ bcr_write_line(fout, "STATION", &i, sout);
+ }
+
+ bcr_write_line(fout, "[DESCRIPTION]", nullptr, nullptr); /* descr. section */
+
+ i = 0;
+ foreach (const Waypoint* wpt, route->waypoint_list) {
+ QString s2;
+
+ i++;
+ QString s1 = wpt->notes;
+ if (s1.isEmpty()) {
+ s1 = wpt->description;
+ }
+
+ if (prefer_shortnames_opt || (s1.isEmpty())) {
+ s2 = s1;
+ s1 = wpt->shortname;
+ } else {
+ s2 = wpt->shortname;
+ }
+
+ if (s1.isEmpty()) {
+ s1 = QString();
+ } else {
+ s1 = csv_stringclean(s1, ",\t\r\n");
+ }
+ if (s2.isEmpty()) {
+ s2 = QString();
+ } else {
+ s2 = csv_stringclean(s2, ",\t\r\n");
+ }
+
+ if (sout.isEmpty()) {
+ sout = QString("%1,%2,@,0").arg(s1, s1);
+ } else {
+ sout = QString("%1,%2,@,0").arg(s1, s2);
+ }
+
+ bcr_write_line(fout, "STATION", &i, sout);
+ }
+
+ bcr_write_line(fout, "[ROUTE]", nullptr, nullptr); /* route section */
+
+ sout = QString::number(emin) + "," +
+ QString::number(nmax) + "," +
+ QString::number(emax) + "," +
+ QString::number(nmin);
+ bcr_write_line(fout, "ROUTERECT", nullptr, sout);
+}
+
+static void
+bcr_data_write()
+{
+ target_rte_num = 1;
+
+ if (rtenum_opt != nullptr) {
+ target_rte_num = atoi(rtenum_opt);
+ if (((unsigned)target_rte_num > route_count()) || (target_rte_num < 1))
+ fatal(MYNAME ": invalid route number %d (1..%d))!\n",
+ target_rte_num, route_count());
+ }
+ curr_rte_num = 0;
+ route_disp_all(bcr_route_header, nullptr, nullptr);
+}
+
+ff_vecs_t bcr_vecs = {
+ ff_type_file,
+ { ff_cap_none, ff_cap_none, (ff_cap)(ff_cap_read | ff_cap_write)},
+ bcr_rd_init,
+ bcr_wr_init,
+ bcr_rd_deinit,
+ bcr_wr_deinit,
+ bcr_data_read,
+ bcr_data_write,
+ nullptr,
+ &bcr_args,
+ CET_CHARSET_MS_ANSI, 0, /* CET-REVIEW */
+ NULL_POS_OPS
+};
--- /dev/null
+/*
+
+ Support for IGN Rando track files.
+
+ Copyright (C) 2005,2006 Olaf Klein, o.b.klein@gpsbabel.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+
+#include <cstdio> // for sscanf
+#include <cstdlib> // for atoi
+#include <ctime> // for strftime, localtime, time_t, tm
+
+#include <QByteArray> // for QByteArray
+#include <QIODevice> // for QIODevice, QIODeviceBase::ReadOnly
+#include <QList> // for QList
+#include <QString> // for QString, operator==
+#include <QXmlStreamAttributes> // for QXmlStreamAttributes
+#include <QtGlobal> // for QT_VERSION, QT_VERSION_CHECK, qPrintable
+
+#include "defs.h"
+#include "gbfile.h" // for gbfprintf, gbfclose, gbfopen, gbfile
+#include "src/core/datetime.h" // for DateTime
+#include "src/core/file.h" // for File
+#include "xmlgeneric.h" // for xg_callback, xg_string, cb_cdata, xml_deinit, xml_init, xml_readunicode, cb_start, cb_end, xg_cb_type, xg_tag_mapping
+
+
+#define MYNAME "IGNRando"
+
+#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
+static QString rd_fname;
+#endif
+static gbfile* fout;
+
+static route_head* track;
+static Waypoint* wpt;
+static int track_index; /* index of track we'll write */
+static int track_num; /* current index of track within track_disp_all */
+
+static int xmlpoints;
+
+/* options */
+static char* index_opt = nullptr;
+
+static QVector<arglist_t> ignr_args = {
+ {"index", &index_opt, "Index of track to write (if more than one in source)", nullptr, ARGTYPE_INT, "1", nullptr , nullptr},
+};
+
+
+static xg_callback ignr_start;
+static xg_callback ignr_nb_etapes, ignr_descr;
+static xg_callback ignr_etape_begin, ignr_etape_end;
+static xg_callback ignr_etape_pos, ignr_etape_alt;
+
+static
+xg_tag_mapping ignr_xml_map[] = {
+ { ignr_start, cb_start, "/RANDONNEE" },
+ { ignr_nb_etapes, cb_cdata, "/RANDONNEE/INFORMATIONS/NB_ETAPES" },
+ { ignr_descr, cb_cdata, "/RANDONNEE/INFORMATIONS/DESCRIPTION" },
+ { ignr_etape_begin, cb_start, "/RANDONNEE/ETAPE" },
+ { ignr_etape_end, cb_end, "/RANDONNEE/ETAPE" },
+ { ignr_etape_pos, cb_cdata, "/RANDONNEE/ETAPE/POSITION" },
+ { ignr_etape_alt, cb_cdata, "/RANDONNEE/ETAPE/ALTITUDE" },
+ { nullptr, (xg_cb_type)0, nullptr }
+};
+
+static void
+ignr_xml_error(int condition)
+{
+ if (condition != 0) {
+ fatal(MYNAME ": Error in XML structure!\n");
+ }
+}
+
+/* xmlgeneric callbacks */
+
+static void
+ignr_start(xg_string, const QXmlStreamAttributes*)
+{
+ ignr_xml_error((track != nullptr));
+
+ track = new route_head;
+ track_add_head(track);
+}
+
+static void
+ignr_nb_etapes(xg_string args, const QXmlStreamAttributes*)
+{
+ xmlpoints = args.toInt();
+}
+
+static void
+ignr_descr(xg_string args, const QXmlStreamAttributes*)
+{
+ ignr_xml_error((track == nullptr));
+ track->rte_desc = args;
+}
+
+static void
+ignr_etape_begin(xg_string, const QXmlStreamAttributes*)
+{
+ ignr_xml_error((wpt != nullptr));
+
+ wpt = new Waypoint;
+}
+
+static void
+ignr_etape_end(xg_string, const QXmlStreamAttributes*)
+{
+ ignr_xml_error((track == nullptr) || (wpt == nullptr));
+
+ track_add_wpt(track, wpt);
+ wpt = nullptr;
+}
+
+static void
+ignr_etape_pos(xg_string args, const QXmlStreamAttributes*)
+{
+ ignr_xml_error((wpt == nullptr) || (args.isEmpty()));
+
+ if (2 != sscanf(STRFROMUNICODE(args), "%lf,%lf", &wpt->latitude, &wpt->longitude)) {
+ fatal(MYNAME ": Invalid coordinates \"%s\"!\n", qPrintable(args));
+ }
+}
+
+static void
+ignr_etape_alt(xg_string args, const QXmlStreamAttributes*)
+{
+ ignr_xml_error((wpt == nullptr));
+ if (args == nullptr) {
+ return;
+ }
+
+ if (1 != sscanf(STRFROMUNICODE(args), "%lf", &wpt->altitude)) {
+ fatal(MYNAME ": Invalid altitude \"%s\"!\n", qPrintable(args));
+ }
+}
+
+/* callbacks registered in ignr_vecs */
+
+static void
+ignr_rd_init(const QString& fname)
+{
+#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
+ xml_init(fname, ignr_xml_map, nullptr);
+#else
+ rd_fname = fname;
+ xml_init(nullptr, ignr_xml_map, nullptr);
+#endif
+ wpt = nullptr;
+ track = nullptr;
+}
+
+static void
+ignr_rd_deinit()
+{
+ xml_deinit();
+#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
+ rd_fname.clear();
+#endif
+}
+
+static void
+ignr_read()
+{
+#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
+ // QXmlStreamReader had access to the windows-1252 QTextCodec that we expect
+ // to find in the XMLDecl.
+ xml_read();
+#else
+ // QXmlStreamReader doesn't have access to a windows-1252 QStringDecoder,
+ // and will throw an error if we pass a QIODevice when it sees windows-1252
+ // in the XMLDecl.
+ // Therfore we must decode the input manually and pass a QString.
+ // With a QString QXmlStreamReader will ignore the XMLDecl.
+ gpsbabel::File file(rd_fname);
+ file.open(QIODevice::ReadOnly);
+ xml_readunicode(STRTOUNICODE(file.readAll()));
+ file.close();
+#endif
+}
+
+/* write support */
+
+/* callbacks registered in ignr_vecs */
+
+static void
+ignr_rw_init(const QString& fname)
+{
+ fout = gbfopen(fname, "w", MYNAME);
+}
+
+static void
+ignr_rw_deinit()
+{
+ gbfclose(fout);
+}
+
+static void
+ignr_write_track_hdr(const route_head* track_hdr)
+{
+ track_num++;
+
+ if (track_num != track_index) {
+ return;
+ }
+
+ gbfprintf(fout, "\t<INFORMATIONS>\n");
+ gbfprintf(fout, "\t\t<NB_ETAPES>%d</NB_ETAPES>\n", track_hdr->rte_waypt_ct());
+ if (!track_hdr->rte_desc.isEmpty()) {
+ gbfprintf(fout, "\t\t<DESCRIPTION>%s</DESCRIPTION>\n", STRFROMUNICODE(track_hdr->rte_desc));
+ }
+ gbfprintf(fout, "\t</INFORMATIONS>\n");
+}
+
+static void
+ignr_write_waypt(const Waypoint* waypoint)
+{
+ if (track_num != track_index) {
+ return;
+ }
+
+ gbfprintf(fout, "\t<ETAPE>\n");
+ gbfprintf(fout, "\t\t<POSITION>%3.6f,%3.6f</POSITION>\n", waypoint->latitude, waypoint->longitude);
+ if (waypoint->altitude != unknown_alt) {
+ gbfprintf(fout, "\t\t<ALTITUDE>%3.6f</ALTITUDE>\n", waypoint->altitude);
+ }
+ gbfprintf(fout, "\t</ETAPE>\n");
+}
+
+static void
+ignr_write()
+{
+ time_t now;
+ struct tm tm;
+ char buff[32];
+
+ if (index_opt != nullptr) {
+ track_index = atoi(index_opt);
+ if ((track_index < 1) || (track_index > (int) track_count()))
+ fatal(MYNAME ": Invalid track index %d (we have currently %d track(s))!\n",
+ track_index, track_count());
+ } else {
+ track_index = 1;
+ }
+ track_num = 0;
+
+ now = current_time().toTime_t();
+ tm = *localtime(&now);
+
+ gbfprintf(fout, "<?xml version=\"1.0\" encoding=\"windows-1252\"?>\n");
+ gbfprintf(fout, "<RANDONNEE>\n");
+ gbfprintf(fout, "\t<ENTETE>\n");
+ gbfprintf(fout, "\t\t<VERSION_XML>1.1</VERSION_XML>\n");
+ gbfprintf(fout, "\t\t<VERSION_BASE>IHA03AA</VERSION_BASE>\n");
+
+ strftime(buff, sizeof(buff), "%d/%m/%Y", &tm);
+ gbfprintf(fout, "\t\t<DATE>%s</DATE>\n", buff);
+ strftime(buff, sizeof(buff), "%H:%M:%S", &tm);
+ gbfprintf(fout, "\t\t<HEURE>%s</HEURE>\n", buff);
+
+ gbfprintf(fout, "\t</ENTETE>\n");
+ track_disp_all(ignr_write_track_hdr, nullptr, ignr_write_waypt);
+ gbfprintf(fout, "</RANDONNEE>\n");
+}
+
+ff_vecs_t ignr_vecs = {
+ ff_type_file,
+ { ff_cap_none, (ff_cap)(ff_cap_read | ff_cap_write), ff_cap_none },
+ ignr_rd_init,
+ ignr_rw_init,
+ ignr_rd_deinit,
+ ignr_rw_deinit,
+ ignr_read,
+ ignr_write,
+ nullptr,
+ &ignr_args,
+ CET_CHARSET_MS_ANSI, 1
+ , NULL_POS_OPS
+};
--- /dev/null
+/*
+ IGO8 Track Format
+
+ Copyright (C) 2008 Dustin Johnson, Dustin@Dustinj.us
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ July 26, 2008 - Dustin: Added tracknum, title, and description options
+ July 26, 2008 - Dustin: Validated the new code for char to Unicode conversion
+ */
+
+
+/*
+ iGo8 (*.trk) Format Overview
+
+ |------------------------------| <--\
+ | ID Block (20B) | |
+ |------------------------------| |
+ | | |
+ | |
+ | | H
+ | | e
+ | | a
+ | Description Block (256B) | d
+ | | e
+ | | r
+ | |
+ | | |
+ | | |
+ | | |
+ |------------------------------| <--/
+ | Information Block (12B) |
+ |------------------------------|
+ | Waypoint 1 |
+ |------------------------------|
+ | Waypoint 2 |
+ |------------------------------|
+ | Waypoint 3 |
+ |------------------------------|
+ | ... |
+ |------------------------------|
+
+ ID Block: defined by igo8_id_block
+ Description Block: Two null-terminated unicode 2 strings.
+ The first is the title of the track,
+ the second is the description.
+ Information Block: defined by igo8_information_block
+ Waypoint: defined by igo8_point
+
+*/
+
+#include <cstdio> // for SEEK_SET
+#include <cstdint>
+#include <cstdlib> // for atoi
+#include <cstring> // for memset
+
+#include <QChar> // for QChar
+#include <QString> // for QString
+#include <QVector> // for QVector
+
+#include "defs.h"
+#include "gbfile.h" // for gbfwrite, gbfclose, gbfseek, gbfgetint32, gbfread, gbfile, gbfopen_le
+#include "src/core/datetime.h" // for DateTime
+
+
+#define FLOAT_TO_INT(x) ((int)((x) + ((x)<0?-0.5:0.5)))
+#define IGO8_HEADER_SIZE (sizeof(igo8_id_block) + 256)
+#define MYNAME "IGO8"
+
+struct igo8_id_block {
+ uint32_t unknown_1;
+ uint32_t unknown_2;
+ uint32_t unknown_3;
+ uint32_t track_number;
+ uint32_t unknown_4;
+};
+using p_igo8_id_block = igo8_id_block*;
+
+struct igo8_information_block {
+ uint32_t start_time; // In Unix time
+ uint32_t zero; // Doesn't appear to serve a purpose
+ uint32_t total_file_size; // In bytes
+};
+using p_igo8_information_block = igo8_information_block*;
+
+struct igo8_point {
+ uint32_t unix_time;
+ uint32_t lon;
+ uint32_t lat;
+};
+using p_igo8_point = igo8_point*;
+
+// Files
+static gbfile* igo8_file_in;
+static gbfile* igo8_file_out;
+
+// Options
+static char* igo8_option_tracknum = nullptr;
+static char* igo8_option_title = nullptr;
+static char* igo8_option_description = nullptr;
+
+// Internal state
+static uint32_t invented_time;
+static uint32_t point_count;
+static int in_point_count;
+
+// Exported options list
+static QVector<arglist_t> igo8_options = {
+ { "tracknum", &igo8_option_tracknum, "Track identification number", nullptr, ARGTYPE_INT, ARG_NOMINMAX, nullptr },
+ { "title", &igo8_option_title, "Track title", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr },
+ { "description", &igo8_option_description, "Track description", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr },
+};
+
+// Sanity check
+static void igo8_check_type_sizes()
+{
+ if constexpr(sizeof(igo8_point) != 12) {
+ fatal(MYNAME ": igo8_point is %ld bytes instead of the required 12.\n",
+ (long) sizeof(igo8_point));
+ }
+
+ if constexpr(sizeof(igo8_information_block) != 12) {
+ fatal(MYNAME ": igo8_information_block is %ld bytes instead of the required 12.\n",
+ (long) sizeof(igo8_information_block));
+ }
+
+ if constexpr(sizeof(igo8_id_block) != 20) {
+ fatal(MYNAME ": igo8_id_block is %ld bytes instead of the required 20.\n",
+ (long) sizeof(igo8_id_block));
+ }
+}
+
+// Reader initialization callback
+static void igo8_read_init(const QString& fname)
+{
+ igo8_file_in = gbfopen_le(fname, "rb", MYNAME);
+
+ // Make sure that we are in the environment we expect and require
+ igo8_check_type_sizes();
+
+ // Seek past the header and most of the Information Block. Read
+ // the last word for trackpoint count since latest igo8 seems to
+ // zero-pad the files.
+ gbfseek(igo8_file_in, IGO8_HEADER_SIZE + sizeof(igo8_information_block) - 4, SEEK_SET);
+ in_point_count = (gbfgetint32(igo8_file_in) - IGO8_HEADER_SIZE -
+ sizeof(igo8_information_block)) / sizeof(igo8_point);
+}
+
+// Reader callback
+static void igo8_read()
+{
+ igo8_point point;
+
+ auto* track_head = new route_head;
+ track_add_head(track_head);
+
+ while (in_point_count &&
+ gbfread(&point, sizeof(point), 1, igo8_file_in) > 0) {
+ in_point_count--;
+ auto* wpt_tmp = new Waypoint;
+
+ wpt_tmp->latitude = le_read32(&point.lat) / (double)0x800000;
+ wpt_tmp->longitude = le_read32(&point.lon) / (double)0x800000;
+ wpt_tmp->SetCreationTime(le_read32(&point.unix_time));
+
+ track_add_wpt(track_head, wpt_tmp);
+ }
+}
+
+// Reader close callback
+static void igo8_read_deinit()
+{
+ gbfclose(igo8_file_in);
+}
+
+// Writer initialize callback
+static void igo8_write_init(const QString& fname)
+{
+ igo8_file_out = gbfopen_le(fname, "wb", MYNAME);
+
+ igo8_check_type_sizes();
+
+ invented_time = 1;
+ point_count = 0;
+}
+
+// Writer close callback
+static void igo8_write_deinit()
+{
+ uint32_t normalized_file_size;
+
+ // Seek to the start of the third long in the Information Block, this is
+ // where we will write out the total size of the file.
+ gbfseek(igo8_file_out, IGO8_HEADER_SIZE + sizeof(uint32_t)*2, SEEK_SET);
+
+ // The total size of the file is the number of points written + Information block + Header
+ le_write32(&normalized_file_size, sizeof(igo8_point)*(point_count) + sizeof(igo8_information_block) + IGO8_HEADER_SIZE);
+
+ // Write the size
+ gbfwrite(&normalized_file_size, sizeof(normalized_file_size), 1, igo8_file_out);
+
+ gbfclose(igo8_file_out);
+}
+
+// Write point callback
+static void write_igo8_track_point(const Waypoint* wpt)
+{
+ igo8_point point;
+
+ memset(&point, 0, sizeof(point));
+
+ // iGo8 appears to expect a time, if one isn't provided
+ // then we shall make our own, where each point is one
+ // second apart.
+ if (wpt->creation_time.isValid()) {
+ le_write32(&point.unix_time, wpt->GetCreationTime().toTime_t());
+ } else {
+ le_write32(&point.unix_time, invented_time++);
+ }
+
+ // Write the first part of the Information Block, the start time
+ if (point_count == 0) {
+ gbfwrite(&point, sizeof(point), 1, igo8_file_out);
+ }
+
+ le_write32(&point.lon, FLOAT_TO_INT(wpt->longitude * 0x800000));
+ le_write32(&point.lat, FLOAT_TO_INT(wpt->latitude * 0x800000));
+
+ gbfwrite(&point, sizeof(point), 1, igo8_file_out);
+
+ // Count the number of point printed, we will use this at the end to
+ // finish filling out the Information Block.
+ point_count++;
+}
+
+// Write src unicode str to the dst cstring using unicode characters.
+// dst_max_length is in bytes.
+// I have no idea if iGo8 even supports real unicode 2, but is does look like
+// it as every ascii character is a short with the ascii character as the
+// least significant 7 bits.
+static unsigned int print_unicode(char* dst, int dst_max_length, const QString& src)
+{
+ int max_qchars = dst_max_length / 2;
+ if (max_qchars < 1) {
+ // We must have room for the terminator.
+ fatal(MYNAME ": igo8 header overflow.\n");
+ }
+ // Write as many characters from the source as possible
+ // while leaving space for a terminator.
+ int n_src_qchars = src.size() > (max_qchars - 1) ? max_qchars - 1 : src.size();
+ for (int i = 0; i < n_src_qchars; ++i) {
+ le_write16(dst, src.at(i).unicode());
+ dst += 2;
+ }
+ le_write16(dst, 0); // NULL (U+0000) terminator
+
+ return (n_src_qchars + 1) * 2;
+}
+
+static void write_header()
+{
+ char header[IGO8_HEADER_SIZE] = {};
+ igo8_id_block tmp_id_block;
+ auto* id_block = (p_igo8_id_block)header;
+ uint32_t current_position = 0;
+ const char* title = "Title";
+ const char* description = "Description";
+
+ // These values seem to be constant for me, but I have no idea what they are.
+ tmp_id_block.unknown_1 = 0x0000029B;
+ tmp_id_block.unknown_2 = 0x000003E7;
+ tmp_id_block.unknown_3 = 0x00000003;
+
+ // This appears to be a unique number that IDs the track.
+ // It is mono-incrementing and offset by 2 above the track number.
+ // e.g. "Track 1" --> track_number = 3
+ // XXX - Dustin: My guess is that this number is used as the key for the track color, if
+ // XXX - Dustin: multiple tracks have the same color they will be colored the same, just
+ // XXX - Dustin: a guess though.
+ if (igo8_option_tracknum) {
+ tmp_id_block.track_number = atoi(igo8_option_tracknum);
+ } else {
+ tmp_id_block.track_number = 0x00000010;
+ }
+ tmp_id_block.unknown_4 = 0x00000001;
+
+ // Byte swap out to the header buffer.
+ le_write32(&id_block->unknown_1, tmp_id_block.unknown_1);
+ le_write32(&id_block->unknown_2, tmp_id_block.unknown_2);
+ le_write32(&id_block->unknown_3, tmp_id_block.unknown_3);
+ le_write32(&id_block->track_number, tmp_id_block.track_number);
+ le_write32(&id_block->unknown_4, tmp_id_block.unknown_4);
+
+ // Move past the ID block, we have just filled it.
+ current_position += sizeof(*id_block);
+
+ // Set the title of the track
+ // Note: we shorten the length of the potential title by 2 because we need to leave at
+ // least enough room to have a null for the description string that follows it.
+ if (igo8_option_title) {
+ title = igo8_option_title;
+ }
+ current_position += print_unicode((header+current_position), IGO8_HEADER_SIZE - current_position - 2, title);
+
+ // Set the description of the track
+ if (igo8_option_description) {
+ description = igo8_option_description;
+ }
+ current_position += print_unicode((header+current_position), IGO8_HEADER_SIZE - current_position, description);
+
+ gbfwrite(&header, IGO8_HEADER_SIZE, 1, igo8_file_out);
+}
+
+// Writer callback
+static void igo8_write()
+{
+ write_header();
+ track_disp_all(nullptr, nullptr, write_igo8_track_point);
+}
+
+// Callback definitions
+ff_vecs_t igo8_vecs = {
+ ff_type_file,
+ { ff_cap_none, (ff_cap)(ff_cap_read | ff_cap_write), ff_cap_none },
+ igo8_read_init,
+ igo8_write_init,
+ igo8_read_deinit,
+ igo8_write_deinit,
+ igo8_read,
+ igo8_write,
+ nullptr,
+ &igo8_options,
+ CET_CHARSET_UTF8,
+ 1
+ , NULL_POS_OPS
+};
--- /dev/null
+/*
+
+ Support for "MagicMaps" project files (.ikt)
+
+ Copyright (C) 2008 Olaf Klein, o.b.klein@gpsbabel.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+*/
+
+
+#include "defs.h"
+#include "xmlgeneric.h"
+#include <QXmlStreamAttributes>
+
+static QVector<arglist_t> ikt_args = {
+};
+
+#define MYNAME "ikt"
+
+static QString name, text;
+
+static route_head* track;
+static Waypoint* waypt;
+
+static xg_callback iktobj_waypt, iktobj_type, iktobj_name, iktobj_trkpt, iktobj_text;
+
+#define IKTOBJ "/Root/Content/MMGeoObjects/MMGeoObject"
+
+/* Here we are working with wildcards in the tag list.
+ Please ensure that the longest entries comes first */
+
+static
+xg_tag_mapping ikt_map[] = {
+ { iktobj_trkpt, cb_start, IKTOBJ "_*/PathPoints/Point_*/GeoPosition" },
+ { iktobj_type, cb_cdata, IKTOBJ "_*/GeoObjectType" },
+ { iktobj_waypt, cb_start, IKTOBJ "_*/GeoPosition" },
+ { iktobj_name, cb_cdata, IKTOBJ "_*/Name" },
+ { iktobj_text, cb_cdata, IKTOBJ "_*/POIDrawable2D/Text" },
+ { nullptr, (xg_cb_type)0, nullptr }
+};
+
+static void
+ikt_object_end()
+{
+ if (track) {
+ track->rte_name = name;
+ track_add_head(track);
+ } else if (waypt) {
+ waypt->shortname = name;
+ waypt->description = text;
+ waypt_add(waypt);
+ }
+
+ name = QString();
+ text = QString();
+ track = nullptr;
+ waypt = nullptr;
+}
+
+static void
+iktobj_waypt(xg_string, const QXmlStreamAttributes* attrv)
+{
+ if (attrv->hasAttribute("X")) {
+ waypt->longitude = attrv->value("X").toDouble();
+ }
+ if (attrv->hasAttribute("Y")) {
+ waypt->latitude = attrv->value("Y").toDouble();
+ }
+}
+
+static void
+iktobj_trkpt(xg_string args, const QXmlStreamAttributes* attrv)
+{
+ waypt = new Waypoint;
+ iktobj_waypt(args, attrv);
+ track_add_wpt(track, waypt);
+ waypt = nullptr;
+}
+
+static void
+iktobj_name(xg_string args, const QXmlStreamAttributes*)
+{
+ name = args;
+}
+
+static void
+iktobj_text(xg_string args, const QXmlStreamAttributes*)
+{
+ text = args;
+}
+
+static void
+iktobj_type(xg_string args, const QXmlStreamAttributes*)
+{
+ ikt_object_end();
+ switch (args.toInt()) {
+ case 0:
+ waypt = new Waypoint;
+ break;
+ case 1:
+ track = new route_head;
+ break;
+ default:
+ fatal(MYNAME ": Unknown object type %s!\n", qPrintable(args));
+ }
+}
+
+static void
+ikt_rd_init(const QString& fname)
+{
+ xml_init(fname, ikt_map, nullptr);
+
+ track = nullptr;
+ waypt = nullptr;
+ name = QString();
+ text = QString();
+}
+
+static void
+ikt_read()
+{
+ xml_read();
+}
+
+static void
+ikt_rd_deinit()
+{
+ ikt_object_end();
+ xml_deinit();
+}
+
+ff_vecs_t ik3d_vecs = {
+ ff_type_file,
+ {
+ ff_cap_read, /* waypoints */
+ ff_cap_read, /* tracks */
+ ff_cap_none /* routes */
+ },
+ ikt_rd_init,
+ nullptr,
+ ikt_rd_deinit,
+ nullptr,
+ ikt_read,
+ nullptr,
+ nullptr,
+ &ikt_args,
+ CET_CHARSET_UTF8, 1
+ , NULL_POS_OPS
+};
--- /dev/null
+/*
+ Access Nokia Landmark Exchange files.
+
+ Copyright (C) 2007 Robert Lipe, robertlipe+source@gpsbabel.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ */
+
+
+/*
+ * Nokia's Landmark Exchange (LMX) format is a straight-forward XML
+ * format. Though they do support a compact binary representation,
+ * we don't implement that at this time in GPSBabel.
+ */
+
+#include <QString> // for QString
+#include <QXmlStreamAttributes> // for QXmlStreamAttributes
+
+#include "defs.h"
+#include "gbfile.h" // for gbfputc, gbfprintf, gbfclose, gbfopen, gbfputcstr, gbfputs, gbfile, gbfputuint16
+#include "xmlgeneric.h" // for cb_cdata, xg_callback, xg_string, cb_end, cb_start, xg_cb_type, xml_deinit, xml_init, xml_read, xg_tag_mapping
+
+
+static gbfile* ofd;
+static Waypoint* wpt_tmp;
+static QString urllink;
+static QString urllinkt;
+static char* binary = nullptr;
+
+#define MYNAME "lmx"
+
+static
+QVector<arglist_t> lmx_args = {
+ {
+ "binary", &binary,
+ "Compact binary representation",
+ nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+ },
+};
+
+/*
+ * Writer
+ */
+
+
+static void
+lmx_wr_init(const QString& fname)
+{
+ ofd = gbfopen(fname, "w", MYNAME);
+}
+
+static void
+lmx_wr_deinit()
+{
+ gbfclose(ofd);
+}
+
+static const char*
+lmx_stag(int tag)
+{
+ switch (tag) {
+ case 0xC5:
+ return "lmx";
+ case 0x46:
+ return "landmarkCollection";
+ case 0x47:
+ return "landmark";
+ case 0x48:
+ return "name";
+ case 0x49:
+ return "description";
+ case 0x4A:
+ return "coordinates";
+ case 0x4B:
+ return "latitude";
+ case 0x4C:
+ return "longitude";
+ case 0x4D:
+ return "altitude";
+ case 0x4E:
+ return "horizontalAccuracy";
+ case 0x4F:
+ return "verticalAccuracy";
+ case 0x50:
+ return "timeStamp";
+ case 0x51:
+ return "coverageRadius";
+ case 0x52:
+ return "category";
+ case 0x53:
+ return "id";
+ case 0x54:
+ return "addressInfo";
+ case 0x55:
+ return "country";
+ case 0x56:
+ return "countryCode";
+ case 0x57:
+ return "state";
+ case 0x58:
+ return "county";
+ case 0x59:
+ return "city";
+ case 0x5A:
+ return "district";
+ case 0x5B:
+ return "postalCode";
+ case 0x5C:
+ return "crossing1";
+ case 0x5D:
+ return "crossing2";
+ case 0x5E:
+ return "street";
+ case 0x5F:
+ return "buildingName";
+ case 0x60:
+ return "buildingFloor";
+ case 0x61:
+ return "buildingZone";
+ case 0x62:
+ return "buildingRoom";
+ case 0x63:
+ return "extension";
+ case 0x64:
+ return "phoneNumber";
+ case 0x65:
+ return "mediaLink";
+ case 0x66:
+ return "mime";
+ case 0x67:
+ return "url";
+ default:
+ return nullptr;
+ }
+}
+
+static void
+lmx_indent(int count)
+{
+ for (int i = 0; i<count; i++) {
+ gbfputc('\t', ofd);
+ }
+}
+
+static void
+lmx_start_tag(int tag, int indent)
+{
+ if (binary) {
+ gbfputc(tag, ofd);
+ } else {
+ lmx_indent(indent);
+ gbfprintf(ofd, "<lm:%s>", lmx_stag(tag));
+ }
+}
+
+static void
+lmx_end_tag(int tag, int indent)
+{
+ if (binary) {
+ gbfputc(0x01, ofd);
+ } else {
+ lmx_indent(indent);
+ gbfprintf(ofd, "</lm:%s>\n", lmx_stag(tag));
+ }
+}
+
+static void
+lmx_write_xml(int tag, const QString& data, int indent)
+{
+ lmx_start_tag(tag, indent);
+
+ if (binary) {
+ gbfputc(0x03, ofd); // inline string follows
+ gbfputcstr(CSTR(data), ofd);
+ } else {
+ char* tmp_ent = xml_entitize(CSTR(data));
+ gbfputs(tmp_ent, ofd);
+ xfree(tmp_ent);
+ }
+
+ lmx_end_tag(tag, 0);
+}
+
+static void
+lmx_print(const Waypoint* wpt)
+{
+ /*
+ * Desperation time, try very hard to get a good shortname
+ */
+ QString odesc = wpt->notes;
+ if (odesc.isEmpty()) {
+ odesc = wpt->description;
+ }
+ if (odesc.isEmpty()) {
+ odesc = wpt->shortname;
+ }
+
+ QString oname = global_opts.synthesize_shortnames ? odesc : wpt->shortname;
+
+ lmx_start_tag(0x47, 2); // landmark
+ if (!binary) {
+ gbfputc('\n', ofd);
+ }
+ if (!oname.isEmpty()) {
+ lmx_write_xml(0x48, oname, 3); // name
+ }
+ if (!wpt->description.isEmpty()) {
+ lmx_write_xml(0x49, wpt->description, 3); // description
+ }
+ lmx_start_tag(0x4A, 3); // coordinates
+ if (!binary) {
+ gbfputc('\n', ofd);
+ }
+
+ lmx_write_xml(0x4B, QString::number(wpt->latitude, 'f'), 4); // latitude
+
+ lmx_write_xml(0x4C, QString::number(wpt->longitude, 'f'), 4); // longitude
+
+ if (wpt->altitude && (wpt->altitude != unknown_alt)) {
+ lmx_write_xml(0x4D, QString::number(wpt->altitude, 'f'), 4); // altitude
+ }
+ lmx_end_tag(0x4A, 3); // coordinates
+
+ if (wpt->HasUrlLink()) {
+ lmx_start_tag(0x65, 3); // mediaLink
+ if (!binary) {
+ gbfputc('\n', ofd);
+ }
+ UrlLink link = wpt->GetUrlLink();
+ if (!link.url_link_text_.isEmpty()) {
+ lmx_write_xml(0x48, link.url_link_text_, 4); // name
+ }
+ lmx_write_xml(0x67, link.url_, 4); // url
+ lmx_end_tag(0x65, 3); // mediaLink
+ }
+
+ lmx_end_tag(0x47, 2); // landmark
+}
+
+
+static void
+lmx_write()
+{
+ if (binary) {
+ gbfputc(0x03, ofd); // WBXML version 1.3
+ gbfputuint16(0x04A4, ofd); // "-//NOKIA//DTD LANDMARKS 1.0//EN"
+ gbfputc(106, ofd); // Charset=UTF-8
+ gbfputc(0x00, ofd); // empty string table
+ gbfputc(0xC5, ofd); // lmx
+ gbfputc(0x05, ofd); // xmlns=http://www.nokia.com/schemas/location/landmarks/
+ gbfputc(0x85, ofd); // 1/0/
+ gbfputc(0x06, ofd); // xmlns:xsi=
+ gbfputc(0x86, ofd); // http://www.w3.org/2001/XMLSchema-instance
+ gbfputc(0x07, ofd); // xsi:schemaLocation=http://www.nokia.com/schemas/location/landmarks/
+ gbfputc(0x85, ofd); // 1/0/
+ gbfputc(0x87, ofd); // whitespace
+ gbfputc(0x88, ofd); // lmx.xsd
+ gbfputc(0x01, ofd); // END lmx attributes
+ } else {
+ gbfprintf(ofd, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ gbfprintf(ofd, "<lm:lmx xmlns:lm=\"http://www.nokia.com/schemas/location/landmarks/1/0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.nokia.com/schemas/location/landmarks/1/0/ lmx.xsd\">\n");
+ }
+
+ lmx_start_tag(0x46, 1); // landmarkCollection
+ if (!binary) {
+ gbfputc('\n', ofd);
+ }
+ waypt_disp_all(lmx_print);
+ lmx_end_tag(0x46, 1); // landmarkCollection
+ lmx_end_tag(0xC5, 0); // lmx
+}
+
+/*
+ * Reader
+ */
+
+static xg_callback lmx_lm_start, lmx_lm_end;
+static xg_callback lmx_lm_name,lmx_lm_desc;
+static xg_callback lmx_lm_lat, lmx_lm_lon, lmx_lm_alt;
+static xg_callback lmx_lm_mlink_s, lmx_lm_mlink_e;
+static xg_callback lmx_lm_link, lmx_lm_linkt;
+
+static xg_tag_mapping gl_map[] = {
+#define LM "/lm:lmx/lm:landmarkCollection/lm:landmark"
+ { lmx_lm_start, cb_start, LM },
+ { lmx_lm_end, cb_end, LM },
+ { lmx_lm_name, cb_cdata, LM "/lm:name" },
+ { lmx_lm_desc, cb_cdata, LM "/lm:description" },
+ { lmx_lm_lat, cb_cdata, LM "/lm:coordinates/lm:latitude" },
+ { lmx_lm_lon, cb_cdata, LM "/lm:coordinates/lm:longitude" },
+ { lmx_lm_alt, cb_cdata, LM "/lm:coordinates/lm:altitude" },
+ { lmx_lm_mlink_s, cb_start, LM "/lm:mediaLink" },
+ { lmx_lm_link, cb_cdata, LM "/lm:mediaLink/lm:url" },
+ { lmx_lm_linkt, cb_cdata, LM "/lm:mediaLink/lm:name" },
+ { lmx_lm_mlink_e, cb_end, LM "/lm:mediaLink" },
+ { nullptr, (xg_cb_type)0, nullptr}
+};
+
+static void
+lmx_rd_init(const QString& fname)
+{
+ xml_init(fname, gl_map, nullptr);
+}
+
+static void
+lmx_read()
+{
+ xml_read();
+}
+
+static void
+lmx_rd_deinit()
+{
+ xml_deinit();
+}
+
+
+
+static void
+lmx_lm_start(xg_string, const QXmlStreamAttributes*)
+{
+ wpt_tmp = new Waypoint;
+}
+
+static void
+lmx_lm_end(xg_string, const QXmlStreamAttributes*)
+{
+ waypt_add(wpt_tmp);
+}
+
+static void
+lmx_lm_lat(xg_string args, const QXmlStreamAttributes*)
+{
+ wpt_tmp->latitude = args.toDouble();
+}
+
+static void
+lmx_lm_lon(xg_string args, const QXmlStreamAttributes*)
+{
+ wpt_tmp->longitude = args.toDouble();
+}
+
+static void
+lmx_lm_alt(xg_string args, const QXmlStreamAttributes*)
+{
+ wpt_tmp->altitude = args.toDouble();
+}
+
+static void
+lmx_lm_name(xg_string args, const QXmlStreamAttributes*)
+{
+ wpt_tmp->shortname = args;
+}
+
+static void
+lmx_lm_desc(xg_string args, const QXmlStreamAttributes*)
+{
+ wpt_tmp->description = args;
+}
+
+static void
+lmx_lm_mlink_s(xg_string, const QXmlStreamAttributes*)
+{
+ urllink = urllinkt = QString();
+}
+
+static void
+lmx_lm_link(xg_string args, const QXmlStreamAttributes*)
+{
+ urllink = args;
+}
+
+static void
+lmx_lm_linkt(xg_string args, const QXmlStreamAttributes*)
+{
+ urllinkt = args;
+}
+
+static void
+lmx_lm_mlink_e(xg_string, const QXmlStreamAttributes*)
+{
+ waypt_add_url(wpt_tmp, urllink, urllinkt);
+}
+
+
+ff_vecs_t lmx_vecs = {
+ ff_type_file,
+ {
+ (ff_cap)(ff_cap_read | ff_cap_write), /* waypoints */
+ ff_cap_none, /* tracks */
+ ff_cap_none /* routes */
+ },
+ lmx_rd_init,
+ lmx_wr_init,
+ lmx_rd_deinit,
+ lmx_wr_deinit,
+ lmx_read,
+ lmx_write,
+ nullptr,
+ &lmx_args,
+ CET_CHARSET_UTF8, 0 /* CET-REVIEW */
+ , NULL_POS_OPS
+};
--- /dev/null
+/*
+
+ Support for MapAsia (.tr7) track file format.
+
+ Copyright (C) 2008 Olaf Klein, o.b.klein@gpsbabel.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ */
+
+#include <cmath> // for fabs
+#include <cstring> // for memset
+
+#include <QDate> // for QDate
+#include <QDateTime> // for QDateTime
+#include <QString> // for QString
+#include <QTime> // for QTime
+#include <Qt> // for UTC
+#include <QtGlobal> // for foreach
+
+#include "defs.h"
+#include "gbfile.h" // for gbfclose, gbfeof, gbfgetint32, gbfputint32, gbfread, gbfwrite, gbfile, gbfopen_le
+#include "session.h" // for curr_session
+#include "src/core/datetime.h" // for DateTime
+
+
+#define MYNAME "mapasia"
+
+#define TR7_TRACK_MAGIC 0x223EADB
+
+#define TR7_S_SIZE 32
+
+#define TR7_S_YEAR 0
+#define TR7_S_MONTH 2
+#define TR7_S_DAY 6
+#define TR7_S_HOUR 8
+#define TR7_S_MIN 10
+#define TR7_S_SEC 12
+#define TR7_S_LON 16
+#define TR7_S_LAT 20
+#define TR7_S_SPEED 24
+#define TR7_S_COURSE 26
+#define TR7_S_VALID 28
+#define TR7_S_FIX 29
+
+static gbfile* fin, *fout;
+static const Waypoint* wpt_tmp;
+static const route_head* trk_tmp;
+static int course_tmp, speed_tmp;
+
+static
+QVector<arglist_t> tr7_args = {
+};
+
+/*******************************************************************************
+* %%% R E A D E R %%% *
+*******************************************************************************/
+
+static void
+tr7_rd_init(const QString& fname)
+{
+ fin = gbfopen_le(fname, "rb", MYNAME);
+}
+
+static void
+tr7_read()
+{
+ route_head* trk = nullptr;
+ Waypoint* prev = nullptr;
+
+ unsigned int magic = gbfgetint32(fin);
+ if (magic != TR7_TRACK_MAGIC) {
+ fatal(MYNAME ": Invalid magic number in header (%X, but %X expected)!\n", magic, TR7_TRACK_MAGIC);
+ }
+
+ while (! gbfeof(fin)) {
+ unsigned char buff[TR7_S_SIZE];
+
+ gbfread(buff, 1, sizeof(buff), fin);
+
+ double lat = (double)le_read32(&buff[TR7_S_LAT]) / 1000000.0;
+ double lon = (double)le_read32(&buff[TR7_S_LON]) / 1000000.0;
+
+ if ((fabs(lat) > 90) || (fabs(lon) > 180)) { /* that really happens */
+ trk = nullptr;
+ continue;
+ }
+
+ QDate date(le_read16(&buff[TR7_S_YEAR]),
+ buff[TR7_S_MONTH],
+ buff[TR7_S_DAY]);
+ QTime time(buff[TR7_S_HOUR],
+ buff[TR7_S_MIN],
+ buff[TR7_S_SEC]);
+ if (!date.isValid() || !time.isValid()) {
+ continue;
+ }
+
+ float speed = KPH_TO_MPS(le_read16(&buff[TR7_S_SPEED]));
+ float course = 360 - le_read16(&buff[TR7_S_COURSE]);
+ if ((speed < 0) || (course > 360) || (course < 0)) {
+ continue;
+ }
+
+ auto* wpt = new Waypoint;
+
+ wpt->latitude = lat;
+ wpt->longitude = lon;
+
+ wpt->SetCreationTime(QDateTime(date, time, Qt::UTC));
+
+ WAYPT_SET(wpt, course, course);
+ WAYPT_SET(wpt, speed, speed);
+
+#if 0 /* unsure, not validated items */
+ wpt->fix = buff[TR7_S_FIX];
+ if (buff[TR7_S_VALID] != 'A') {
+ delete wpt;
+ continue;
+ }
+#endif
+ if (waypt_speed(prev, wpt) > 9999.9) { /* filter out some bad trackpoints */
+ delete wpt;
+ continue;
+ }
+
+ if (prev) { /* other track or bad timestamp */
+ if (wpt->creation_time.isValid() && (prev->creation_time.toTime_t() > wpt->creation_time.toTime_t())) {
+ trk = nullptr;
+ } else if (waypt_distance(prev, wpt) > 9999.9) {
+ trk = nullptr;
+ }
+ }
+
+ if (! trk) {
+ trk = new route_head;
+ track_add_head(trk);
+ }
+ track_add_wpt(trk, wpt);
+ prev = wpt;
+ }
+}
+
+static void
+tr7_check_after_read_head_cb(const route_head* trk)
+{
+ trk_tmp = trk;
+ course_tmp = 0;
+ speed_tmp = 0;
+}
+
+static void
+tr7_check_after_read_wpt_cb(const Waypoint* wpt)
+{
+ if (wpt->speed != 0) {
+ speed_tmp = 1;
+ }
+ if (wpt->course != 360.0) {
+ course_tmp = 1;
+ }
+}
+
+static void
+tr7_check_after_read_trailer_cb(const route_head* trk)
+{
+ foreach (Waypoint* wpt, trk->waypoint_list) {
+ if (speed_tmp == 0) {
+ WAYPT_UNSET(wpt, speed);
+ }
+ if (course_tmp == 0) {
+ WAYPT_UNSET(wpt, course);
+ wpt->course = 0;
+ }
+ }
+}
+
+static void
+tr7_rd_deinit()
+{
+ track_disp_session(curr_session(),
+ tr7_check_after_read_head_cb,
+ tr7_check_after_read_trailer_cb,
+ tr7_check_after_read_wpt_cb);
+ gbfclose(fin);
+}
+
+/*******************************************************************************
+* %%% W R I T E R %%% *
+*******************************************************************************/
+
+static void
+tr7_disp_track_head_cb(const route_head*)
+{
+ wpt_tmp = nullptr;
+}
+
+static void
+tr7_disp_waypt_cb(const Waypoint* wpt)
+{
+ unsigned char buff[TR7_S_SIZE];
+
+ memset(buff, 0, sizeof(buff));
+
+ le_write32(&buff[TR7_S_LON], (int)(wpt->longitude * 1000000.0));
+ le_write32(&buff[TR7_S_LAT], (int)(wpt->latitude * 1000000.0));
+
+ double course;
+ if WAYPT_HAS(wpt, course) {
+ course = wpt->course;
+ } else if (wpt_tmp != nullptr) {
+ course = waypt_course(wpt_tmp, wpt);
+ } else {
+ course = -1;
+ }
+ if (course >= 0) {
+ le_write16(&buff[TR7_S_COURSE], (int)(360 - course));
+ }
+
+ QDateTime dt = wpt->GetCreationTime().toUTC();
+ if (dt.isValid()) {
+ QDate d = dt.date();
+
+ le_write16(&buff[TR7_S_YEAR], d.year());
+ buff[TR7_S_MONTH] = d.month();
+ buff[TR7_S_DAY] = d.day();
+
+ QTime t = dt.time();
+ buff[TR7_S_HOUR] = t.hour();
+ buff[TR7_S_MIN] = t.minute();
+ buff[TR7_S_SEC] = t.second();
+
+ double speed;
+ if WAYPT_HAS(wpt, speed) {
+ speed = wpt->speed;
+ } else if (wpt_tmp != nullptr) {
+ speed = waypt_speed(wpt_tmp, wpt);
+ } else {
+ speed = -1;
+ }
+ if (speed >= 0) {
+ le_write16(&buff[TR7_S_SPEED], (int)MPS_TO_KPH(speed));
+ }
+ }
+ buff[TR7_S_VALID] = 'A'; /* meaning unknown */
+
+#if 0 /* not validated */
+ if (wpt->fix != fix_unknown) {
+ buff[TR7_S_FIX] = wpt->fix;
+ }
+#endif
+ gbfwrite(buff, 1, sizeof(buff), fout);
+
+ wpt_tmp = wpt;
+}
+
+static void
+tr7_wr_init(const QString& fname)
+{
+ fout = gbfopen_le(fname, "wb", MYNAME);
+ gbfputint32(TR7_TRACK_MAGIC, fout);
+}
+
+static void
+tr7_wr_deinit()
+{
+ gbfclose(fout);
+}
+
+static void
+tr7_write()
+{
+ track_disp_all(tr7_disp_track_head_cb, nullptr, tr7_disp_waypt_cb);
+}
+
+/**************************************************************************/
+
+ff_vecs_t mapasia_tr7_vecs = { /* we can read and write tracks */
+ ff_type_file,
+ {
+ ff_cap_none /* waypoints */,
+ (ff_cap)(ff_cap_read | ff_cap_write) /* tracks */,
+ ff_cap_none /* routes */
+ },
+ tr7_rd_init,
+ tr7_wr_init,
+ tr7_rd_deinit,
+ tr7_wr_deinit,
+ tr7_read,
+ tr7_write,
+ nullptr,
+ &tr7_args,
+ CET_CHARSET_UTF8, 1 /* FIXED - CET-REVIEW - */
+ , NULL_POS_OPS
+};
+
+/**************************************************************************/
--- /dev/null
+/*
+ Copyright (C) 2014 Robert Lipe
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ */
+#include "mapfactor.h"
+
+#include <QByteArray> // for QByteArray
+#include <QIODevice> // for QIODevice, operator|, QIODevice::ReadOnly, QIODevice::Text, QIODevice::WriteOnly
+#include <QtGlobal> // for qPrintable
+#include <QStringLiteral> // for QStringLiteral
+#include <QXmlStreamAttributes> // for QXmlStreamAttributes
+#include <QXmlStreamReader> // for QXmlStreamReader, QXmlStreamReader::EndElement, QXmlStreamReader::StartElement
+#include <QXmlStreamWriter> // for QXmlStreamWriter
+
+#include "defs.h" // for Waypoint, fatal, waypt_add, waypt_disp_all
+#include "src/core/file.h" // for File
+#include "src/core/xmlstreamwriter.h" // for XmlStreamWriter
+
+
+#define MYNAME "mapfactor"
+
+void MapfactorFormat::MapfactorRead()
+{
+ Waypoint* wpt = nullptr;
+
+ while (!reader.atEnd()) {
+ auto tag_name = reader.name();
+ if (reader.tokenType()==QXmlStreamReader::StartElement) {
+ if (tag_name == u"item") {
+ wpt = new Waypoint;
+
+ QXmlStreamAttributes a = reader.attributes();
+ wpt->shortname = a.value("name").toString();
+ wpt->latitude = a.value("lat").toDouble() / milliarcseconds;
+ wpt->longitude = a.value("lon").toDouble() / milliarcseconds;
+ }
+ }
+
+ if (reader.tokenType() == QXmlStreamReader::EndElement) {
+ if (wpt && reader.name() == u"item") {
+ waypt_add(wpt);
+ }
+ }
+
+ reader.readNext();
+ }
+}
+
+void
+MapfactorFormat::rd_init(const QString& fname)
+{
+ mapfactor_read_fname = fname;
+}
+
+void
+MapfactorFormat::read()
+{
+ gpsbabel::File file(mapfactor_read_fname);
+ file.open(QIODevice::ReadOnly);
+ reader.setDevice(&file);
+
+ MapfactorRead();
+ if (reader.hasError()) {
+ fatal(MYNAME ":Read error: %s (%s, line %ld, col %ld)\n",
+ qPrintable(reader.errorString()),
+ qPrintable(file.fileName()),
+ (long) reader.lineNumber(),
+ (long) reader.columnNumber());
+ }
+}
+
+void
+MapfactorFormat::wr_init(const QString& fname)
+{
+ oqfile = new gpsbabel::File(fname);
+ oqfile->open(QIODevice::WriteOnly | QIODevice::Text);
+ writer = new gpsbabel::XmlStreamWriter(oqfile);
+
+ writer->setAutoFormatting(true);
+ writer->setAutoFormattingIndent(2);
+ writer->writeStartDocument();
+}
+
+void
+MapfactorFormat::wr_deinit()
+{
+ writer->writeEndDocument();
+ delete writer;
+ writer = nullptr;
+ oqfile->close();
+ delete oqfile;
+ oqfile = nullptr;
+}
+
+void
+MapfactorFormat::mapfactor_waypt_pr(const Waypoint* waypointp) const
+{
+ writer->writeStartElement(QStringLiteral("item"));
+
+ writer->writeAttribute(QStringLiteral("name"), waypointp->shortname);
+ writer->writeAttribute(QStringLiteral("lat"), QString::number(waypointp->latitude * milliarcseconds, 'f', 0));
+ writer->writeAttribute(QStringLiteral("lon"), QString::number(waypointp->longitude * milliarcseconds, 'f', 0));
+ writer->writeEndElement();
+}
+
+void
+MapfactorFormat::write()
+{
+ writer->writeStartElement(QStringLiteral("favourites"));
+ writer->writeAttribute(QStringLiteral("version"), QStringLiteral("1"));
+ // TODO: This could be moved to wr_init, but the pre GPX version put the two
+ // lines above this, so mimic that behaviour exactly.
+ writer->setAutoFormatting(true);
+ auto mapfactor_waypt_pr_lambda = [this](const Waypoint* waypointp)->void {
+ mapfactor_waypt_pr(waypointp);
+ };
+ waypt_disp_all(mapfactor_waypt_pr_lambda);
+ writer->writeEndElement();
+}
--- /dev/null
+/*
+ Copyright (C) 2014 Robert Lipe
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ */
+#ifndef MAPFACTOR_H_INCLUDED_
+#define MAPFACTOR_H_INCLUDED_
+
+#include <QString> // for QString
+#include <QVector> // for QVector
+#include <QXmlStreamReader> // for QXmlStreamReader
+#include <QXmlStreamWriter> // for QXmlStreamWriter
+
+#include "defs.h" // for ff_cap, arglist_t, ff_cap_none, CET_CHARSET_UTF8, Waypoint, ff_cap_read, ff_cap_write, ff_type, ff_type_file
+#include "format.h" // for Format
+#include "src/core/file.h" // for File
+
+
+class MapfactorFormat : public Format
+{
+public:
+ QVector<arglist_t>* get_args() override
+ {
+ return &mapfactor_args;
+ }
+
+ ff_type get_type() const override
+ {
+ return ff_type_file;
+ }
+
+ QVector<ff_cap> get_cap() const override
+ {
+ /* waypoints, tracks, routes */
+ return { (ff_cap)(ff_cap_read | ff_cap_write), ff_cap_none, ff_cap_none };
+ }
+
+ QString get_encode() const override
+ {
+ return CET_CHARSET_UTF8;
+ }
+
+ int get_fixed_encode() const override
+ {
+ return 0;
+ }
+
+ void rd_init(const QString& fname) override;
+ void read() override;
+ void wr_init(const QString& fname) override;
+ void write() override;
+ void wr_deinit() override;
+
+private:
+ /* Constants */
+
+ static constexpr double milliarcseconds = 60.0 * 60.0 * 1000.0;
+
+ /* Member Functions */
+
+ void MapfactorRead();
+ void mapfactor_waypt_pr(const Waypoint* waypointp) const;
+
+ /* Data Members */
+
+ gpsbabel::File* oqfile{};
+ QXmlStreamWriter* writer{};
+
+ QVector<arglist_t> mapfactor_args = {
+ };
+
+ QXmlStreamReader reader;
+ QString mapfactor_read_fname;
+};
+#endif // MAPFACTOR_H_INCLUDED_
--- /dev/null
+/*
+
+ Support for Memory-Map Navigator Overlay Files (.mmo)
+
+ Copyright (C) 2008 Olaf Klein, o.b.klein@gpsbabel.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ */
+
+#include <cassert> // for assert
+#include <cctype> // for isspace
+#include <cerrno> // for errno
+#include <cstdio> // for SEEK_CUR, fprintf, size_t, stdout
+#include <cstdlib> // for abort, strtol
+#include <cstdint>
+#include <cstring> // for strcmp, strlen, memset, strchr, strncmp
+#include <ctime>
+
+#include <QByteArray> // for QByteArray
+#include <QChar> // for operator==, QChar
+#include <QDateTime> // for QDateTime
+#include <QHash> // for QHash, QHash<>::const_iterator
+#include <QLatin1String> // for QLatin1String
+#include <QScopedPointer> // for QScopedPointer
+#include <QString> // for QString, operator==
+#include <QTextCodec> // for QTextCodec, QTextCodec::IgnoreHeader
+#include <QTextEncoder> // for QTextEncoder
+#include <QVector> // for QVector
+#include <Qt> // for CaseInsensitive
+#include <QtGlobal> // for qAsConst, QAddConst<>::Type, foreach, Q_UNUSED
+
+#include "defs.h"
+#include "gbfile.h" // for gbfputc, gbfgetuint16, gbfgetc, gbfgetdbl, gbfgetuint32, gbfputflt, gbfputuint32, gbfgetint16, gbfputdbl, gbfputuint16, gbfclose, gbfread, gbfseek, gbfputint16, gbfwrite, gbfcopyfrom, gbfeof, gbfgetflt, gbfgetint32, gbfile, gbfopen, gbfrewind, gbsize_t
+#include "session.h" // for curr_session, session_t
+#include "src/core/datetime.h" // for DateTime
+
+
+#define MYNAME "mmo"
+
+// #define MMO_DBG
+
+static char* opt_locked, *opt_visible, *opt_version;
+
+static
+QVector<arglist_t> mmo_args = {
+ {
+ "locked", &opt_locked, "Write items 'locked' [default no]", "0",
+ ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+ },
+ {
+ "visible", &opt_visible, "Write items 'visible' [default yes]", "1",
+ ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+ },
+ {
+ "ver", &opt_version, "Write files with internal version [n]", nullptr,
+ ARGTYPE_INT, "17", "18", nullptr
+ },
+};
+
+struct mmo_data_t {
+ int objid; /* internal object id */
+ const char* name;
+ const char* category; /* currently not handled */
+ gpsdata_type type; /* type of "data" */
+ time_t ctime;
+ time_t mtime;
+ int left; /* number of unread route points */
+ void* data; /* can be a waypoint, a route or a track */
+ int refct;
+ mmo_data_t** members;
+ unsigned char visible:1;
+ unsigned char locked:1;
+ unsigned char loaded:1;
+};
+
+static gbfile* fin, *fout;
+static QTextCodec* utf16le_codec{nullptr};
+static QTextCodec* legacy_codec{nullptr};
+static int mmo_version;
+static int mmo_obj_ct;
+static int mmo_object_id;
+static uint32_t mmo_filemark;
+static uint16_t wpt_object_id;
+static uint16_t rte_object_id;
+static uint16_t trk_object_id;
+static uint16_t cat_object_id;
+static uint16_t ico_object_id;
+static uint16_t pos_object_id;
+static uint16_t txt_object_id;
+static gpsdata_type mmo_datatype;
+static const route_head* mmo_rte;
+
+static QHash<QString, int> category_names;
+static QHash<int, QString> icons;
+static QHash<int, mmo_data_t*> objects;
+static QHash<QString, unsigned> mmobjects;
+
+struct mmo_icon_mapping_t {
+ int value;
+ const char* icon;
+};
+
+/* standard icons; no bitmaps in file */
+
+static const mmo_icon_mapping_t mmo_icon_value_table[] = {
+ { 0x00, "Dot" },
+ { 0x01, "House" },
+ { 0x02, "Fuel" },
+ { 0x03, "Car" },
+ { 0x04, "Fish" },
+ { 0x05, "Boat" },
+ { 0x06, "Anchor" },
+ { 0x07, "Wreck" },
+ { 0x08, "Exit" },
+ { 0x09, "Skull" },
+ { 0x0A, "Flag" },
+ { 0x0B, "Camp" },
+ { 0x0C, "Man Overboard" },
+ { 0x0D, "Deer" },
+ { 0x0E, "First Aid" },
+ { 0x0F, "Trackback" },
+ { 0x10, "Tiny dot" },
+ { 0x11, "Triangle" },
+ { 0x12, "Square" },
+ { 0x13, "Circle" },
+ { 0x14, "Green buoy" },
+ { 0x15, "Red buoy" },
+ { 0x16, "Yellow buoy" },
+ { 0x17, "Geocache" },
+
+ { -1, nullptr }
+};
+
+static const uint32_t obj_type_ico = 0x00;
+static const uint32_t obj_type_rte = 0x14;
+static const uint32_t obj_type_trk = 0x1E;
+#ifdef MMO_DBG
+static const uint32_t obj_type_txt = 0x32;
+#endif
+static const uint32_t obj_type_wpt = 0x3C;
+
+/* helpers */
+
+#ifdef MMO_DBG
+static void
+dbgprintf(const char* sobj, const char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+
+ printf(MYNAME "-%s: ", sobj);
+ vprintf(fmt, args);
+ va_end(args);
+}
+
+# define DBG(args) dbgprintf args
+#else
+# define DBG(args) do {} while (0) ;
+#endif
+
+static QString
+mmo_readstr()
+{
+ QString res;
+
+ signed int len = (unsigned)gbfgetc(fin);
+ if (len == 0xFF) {
+ // Next two bytes are either the length (strings longer than 254 chars)
+ // or FE then FF (which is -2) meaning a UTF-16 string
+ len = gbfgetint16(fin);
+ if (len == -2) {
+ // read the new length (single byte)
+ // length is number of "characters" not number of bytes
+ len = (unsigned)gbfgetc(fin);
+ if (len > 0) {
+ QByteArray bytesin = gbfreadbuf(len*2, fin);
+ res = utf16le_codec->toUnicode(bytesin);
+ return res;
+ }
+ // length zero is handled below: returns an empty string
+ } else if (len < 0) {
+ fatal(MYNAME ": Invalid string length (%d)!\n", len);
+ }
+ // positive values of len are for strings longer than 254, handled below:
+ }
+ // length zero returns an empty string
+ if (len) {
+ QByteArray bytesin = gbfreadbuf(len, fin);
+ res = legacy_codec->toUnicode(bytesin);
+ }
+
+ return res;
+}
+
+
+static int
+mmo_fillbuf2(void* buf, const gbsize_t bufsz, const gbsize_t count, const int need_all)
+{
+ if (count > (unsigned int)bufsz) {
+ fatal(MYNAME ": Internal error (bufsz too small)!\n");
+ }
+
+ memset(buf, 0xFF, count);
+ gbsize_t res = gbfread(buf, 1, count, fin);
+ if (need_all && (res < count)) {
+ fatal(MYNAME ": Unexpected end of file!\n");
+ }
+
+ return res;
+}
+#define mmo_fillbuf(a,b,c) mmo_fillbuf2((a),sizeof((a)),(b),(c))
+
+#ifdef MMO_DBG
+static void
+mmo_printbuf(const char* buf, int count, const char* comment)
+{
+ int i;
+ printf("%s", comment);
+ for (i = 0; i < count; i++) {
+ printf("%02X ", buf[i] & 0xFF);
+ }
+ printf("- ");
+ for (i = 0; i < count; i++)
+ if (isprint(buf[i])) {
+ printf("%c", buf[i] & 0xFF);
+ } else {
+ printf(".");
+ }
+ printf("\n");
+ fflush(stdout);
+}
+#endif
+
+/******************************************************************************/
+
+static mmo_data_t*
+mmo_register_object(const int objid, const void* ptr, const gpsdata_type type)
+{
+ auto* data = (mmo_data_t*) xcalloc(1, sizeof(mmo_data_t));
+ data->data = const_cast<void*>(ptr);
+ data->visible = 1;
+ data->locked = 0;
+ data->type = type;
+ data->objid = objid;
+
+ objects.insert(objid, data);
+
+ return data;
+}
+
+
+static int
+mmo_get_objid(const void* ptr)
+{
+ for (auto o = objects.constBegin(); o != objects.constEnd(); ++o) {
+ if (o.value()->data == ptr) {
+ return o.key();
+ }
+ }
+ return 0;
+}
+
+
+static mmo_data_t*
+mmo_get_object(const uint16_t objid)
+{
+ int key = objid | 0x8000;
+ if (!objects.contains(key)) {
+#ifdef MMO_DBG
+ gbfseek(fin, -2, SEEK_CUR);
+ int ni, n;
+ for (ni = 0; (n = gbfgetc(fin)) != EOF; ni++) {
+ DBG(("mmo_get_object", "%04X %02X %c (%d)\n",
+ ni, n, n >= 32 && n <= 126 ? (char)n : '.', n));
+ }
+#endif
+ fatal(MYNAME ": Unregistered object id 0x%04X!\n", objid | 0x8000);
+ }
+
+ return objects.value(key);
+}
+
+static Waypoint*
+mmo_get_waypt(mmo_data_t* data)
+{
+ data->refct++;
+ if (data->refct == 1) {
+ return static_cast<Waypoint*>(data->data);
+ } else {
+ return new Waypoint(*(Waypoint*)data->data);
+ }
+}
+
+static void
+mmo_free_object(mmo_data_t* data)
+{
+ if (data->name) {
+ xfree(data->name);
+ }
+ if ((data->type == wptdata) && (data->refct == 0)) {
+ delete (Waypoint*)data->data;
+ }
+ xfree(data);
+}
+
+
+static void
+mmo_register_icon(const int id, const char* name)
+{
+ icons.insert(id, QString::fromUtf8(name));
+}
+
+
+static mmo_data_t* mmo_read_object();
+
+
+static void
+mmo_end_of_route(mmo_data_t* data)
+{
+ auto* rte = (route_head*) data->data;
+
+ if (mmo_version >= 0x12) {
+#ifdef MMO_DBG
+ const char* sobj = "CObjRoute";
+#endif
+ char buf[7];
+
+ mmo_fillbuf(buf, 7, 1);
+ DBG((sobj, "route data (since 0x12): "));
+#ifdef MMO_DBG
+ mmo_printbuf(buf, 7, "");
+#endif
+ rte->line_color.bbggrr = le_read32(&buf[0]);
+ rte->line_color.opacity = 255 - (buf[6] * 51);
+ DBG((sobj, "color = 0x%06X\n", rte->line_color.bbggrr));
+ DBG((sobj, "transparency = %d (-> %d)\n", buf[6], rte->line_color.opacity));
+ DBG((sobj, "for \"%s\" \n", data->name));
+ }
+
+ if (rte->rte_waypt_ct() == 0) { /* don't keep empty routes */
+ route_del_head(rte);
+ data->data = nullptr;
+ }
+}
+
+
+static void
+mmo_read_category(mmo_data_t* data)
+{
+ int marker = gbfgetuint16(fin);
+
+ if (marker & 0x8000) {
+ DBG(("mmo_read_category", "reading category object\n"));
+ gbfseek(fin, -2, SEEK_CUR);
+ mmo_data_t* tmp = mmo_read_object();
+ if (data) {
+ data->category = tmp->name;
+ }
+ }
+}
+
+
+static void
+mmo_read_CObjIcons(mmo_data_t* data)
+{
+ Q_UNUSED(data);
+#ifdef MMO_DBG
+ const char* sobj = "CObjIcons";
+#endif
+ int icon_id;
+ uint16_t u16;
+
+ DBG((sobj, ":-----------------------------------------------------\n"));
+ DBG((sobj, "name = \"%s\" [ visible=%s, id=0x%04X ]\n",
+ data->name, data->visible ? "yes" : "NO", data->objid));
+
+ if (mmo_version >= 0x18) {
+ u16 = gbfgetuint16(fin);
+ DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
+ u16 = gbfgetuint16(fin);
+ DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
+ u16 = gbfgetuint16(fin);
+ DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
+ u16 = gbfgetuint16(fin);
+ DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
+ }
+ u16 = gbfgetuint16(fin);
+ (void) u16;
+ DBG((sobj, "unknown value = 0x%04X\n", u16));
+ u16 = gbfgetuint16(fin);
+ DBG((sobj, "unknown value = 0x%04X\n", u16));
+ u16 = gbfgetuint16(fin);
+ DBG((sobj, "unknown value = 0x%04X\n", u16));
+
+ while ((icon_id = gbfgetuint32(fin))) {
+ (void) gbfgetuint32(fin);
+ (void) gbfgetuint32(fin);
+ QString name = mmo_readstr();
+ DBG((sobj, "bitmap(0x%08X) = \"%s\"\n", icon_id, qPrintable(name)));
+ mmo_register_icon(icon_id, CSTR(name));
+ // The next four bytes hold the length of the image,
+ // read them and then skip the image data.
+ gbfseek(fin, gbfgetuint32(fin), SEEK_CUR);
+ }
+}
+
+
+static void
+mmo_read_CObjWaypoint(mmo_data_t* data)
+{
+#ifdef MMO_DBG
+ const char* sobj = "CObjWaypoint";
+#endif
+ Waypoint* wpt;
+ mmo_data_t** rtelink = nullptr;
+ char buf[16];
+ int i;
+
+ DBG((sobj, ":-----------------------------------------------------\n"));
+ DBG((sobj, "name = \"%s\" [ visible=%s, id=0x%04X ]\n",
+ data->name, data->visible ? "yes" : "NO", data->objid));
+
+ data->data = wpt = new Waypoint;
+ wpt->shortname = data->name;
+
+ time_t time = data->mtime;
+ if (! time) {
+ time = data->ctime;
+ }
+ if (time > 0) {
+ wpt->SetCreationTime(time);
+ }
+
+ if (mmo_version >= 0x18) {
+ uint16_t u16 = gbfgetuint16(fin);
+ DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
+ u16 = gbfgetuint16(fin);
+ DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
+ u16 = gbfgetuint16(fin);
+ DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
+ u16 = gbfgetuint16(fin);
+ DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
+ (void) u16;
+ }
+
+ wpt->latitude = gbfgetdbl(fin);
+ wpt->longitude = gbfgetdbl(fin);
+
+ DBG((sobj, "trackpoint %d/%d coordinates = %f / %f\n", ctp+1,tp, wpt->latitude, wpt->longitude));
+
+ int rtelinks = gbfgetuint16(fin);
+ if (rtelinks > 0) {
+
+ rtelink = (mmo_data_t**) xcalloc(sizeof(*rtelink), rtelinks);
+ DBG((sobj, "rtelinks = %d\n", rtelinks));
+
+ for (i = 0; i < rtelinks; i++) {
+ DBG((sobj, "read rtelink number %d\n", i + 1));
+ rtelink[i] = mmo_read_object();
+ }
+
+ }
+
+ QString str = mmo_readstr(); /* descr + url */
+ if (str.startsWith("_FILE_ ")) {
+ str.remove(0,7);
+ str = str.trimmed();
+ int index = str.indexOf('\n');
+
+ QString url = str.mid(0, index).trimmed();
+ if (!url.isEmpty()) {
+ wpt->AddUrlLink(url);
+ }
+
+ if (index > 0) {
+ str.remove(0,index + 1);
+ if (!str.isEmpty()) {
+ wpt->notes = str;
+ }
+ }
+
+ if (wpt->HasUrlLink()) {
+ DBG((sobj, "url = \"%s\"\n", wpt->url));
+ }
+ } else if (!str.isEmpty()) {
+ wpt->notes = str;
+ }
+ if (!wpt->notes.isEmpty()) {
+ DBG((sobj, "notes = \"%s\"\n", qPrintable(wpt->notes)));
+ }
+
+ mmo_fillbuf(buf, 12, 1);
+ i = le_read32(&buf[8]); /* icon */
+ if (i != -1) {
+ if (icons.contains(i)) {
+ wpt->icon_descr = icons.value(i);
+ DBG((sobj, "icon = \"%s\"\n", qPrintable(wpt->icon_descr)));
+ }
+#ifdef MMO_DBG
+ else {
+ DBG((sobj, "icon not found for 0x%08X\n", i));
+ }
+#endif
+ }
+
+ wpt->proximity = le_read_float(&buf[4]);
+ if (wpt->proximity) {
+ wpt->wpt_flags.proximity = 1;
+ DBG((sobj, "proximity = %f\n", wpt->proximity));
+ }
+
+ str = mmo_readstr(); /* name on gps ??? option ??? */
+ if (!str.isEmpty()) {
+ wpt->description = wpt->shortname;
+ wpt->shortname = str;
+ DBG((sobj, "name on gps = %s\n", qPrintable(str)));
+ }
+
+ int ux = gbfgetuint32(fin);
+ DBG((sobj, "proximity type = %d\n", ux));
+ (void) ux;
+
+ data->loaded = 1;
+
+ if (rtelink) {
+ xfree(rtelink);
+ } else {
+ waypt_add(mmo_get_waypt(data));
+ }
+}
+
+
+static void
+mmo_read_CObjRoute(mmo_data_t* data)
+{
+#ifdef MMO_DBG
+ const char* sobj = "CObjRoute";
+#endif
+ route_head* rte;
+
+ DBG((sobj, ":-----------------------------------------------------\n"));
+ DBG((sobj, "name = \"%s\" [ visible=%s, id=0x%04X ]\n",
+ data->name, data->visible ? "yes" : "NO", data->objid));
+
+ data->data = rte = new route_head;
+ rte->rte_name = data->name;
+ route_add_head(rte);
+
+ if (mmo_version >= 0x18) {
+ uint16_t u16 = gbfgetuint16(fin);
+ DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
+ u16 = gbfgetuint16(fin);
+ DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
+ u16 = gbfgetuint16(fin);
+ DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
+ u16 = gbfgetuint16(fin);
+ DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
+ (void) u16;
+ }
+
+ int ux = gbfgetc(fin); /* line label */
+ DBG((sobj, "line label = %d\n", ux));
+ (void) ux;
+
+ data->left = gbfgetint16(fin);
+
+ if (data->left <= 0) {
+ if (mmo_version >= 0x12) {
+ char buf[16];
+ mmo_fillbuf(buf, 7, 1);
+ }
+ route_del_head(rte);
+ data->data = nullptr;
+
+ return;
+ }
+
+ while (data->left > 0) {
+ DBG((sobj, "read next waypoint\n"));
+ mmo_data_t* tmp = mmo_read_object();
+ if (tmp && tmp->data && (tmp->type == wptdata)) {
+ Waypoint* wpt;
+
+ /* FIXME: At this point this waypoint maybe not fully loaded (initialized) !!!
+ We need a final procedure to handle this !!! */
+ if (! tmp->loaded) {
+ wpt = new Waypoint;
+ wpt->latitude = 0;
+ wpt->longitude = 0;
+ xasprintf(&wpt->shortname, "\01%p", tmp);
+ } else {
+ wpt = mmo_get_waypt(tmp);
+ }
+
+ route_add_wpt(rte, wpt);
+ data->left--;
+ }
+ }
+
+ if (mmo_version > 0x11) {
+ mmo_end_of_route(data);
+ }
+}
+
+
+static void
+mmo_read_CObjTrack(mmo_data_t* data)
+{
+#ifdef MMO_DBG
+ const char* sobj = "CObjTrack";
+#endif
+
+ DBG((sobj, ":-----------------------------------------------------\n"));
+ DBG((sobj, "name = \"%s\" [ visible=%s, id=0x%04X ]\n",
+ data->name, data->visible ? "yes" : "NO", data->objid));
+
+ auto* trk = new route_head;
+ trk->rte_name = data->name;
+ track_add_head(trk);
+
+ if (mmo_version >= 0x18) {
+ uint16_t u16 = gbfgetuint16(fin);
+ DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
+ u16 = gbfgetuint16(fin);
+ DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
+ u16 = gbfgetuint16(fin);
+ DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
+ u16 = gbfgetuint16(fin);
+ DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
+ Q_UNUSED(u16);
+ }
+
+ int tp = gbfgetint16(fin);
+ DBG((sobj, "track has %d point(s)\n", tp));
+
+ for (int ctp = 0; ctp < tp; ctp++) {
+ auto* wpt = new Waypoint;
+
+ wpt->latitude = gbfgetdbl(fin);
+ wpt->longitude = gbfgetdbl(fin);
+ DBG((sobj, "coordinates = %f / %f\n", wpt->latitude, wpt->longitude));
+ char unk = gbfgetc(fin);
+ DBG((sobj, "Unknown = 0x%02X (%d)\n", unk, unk));
+
+ wpt->SetCreationTime(gbfgetint32(fin));
+ wpt->altitude = gbfgetflt(fin);
+
+ if (unk != 0) {
+ uint16_t ux = gbfgetuint16(fin);
+ DBG((sobj, "unknown value = 0x%04X (%d)\n", ux, ux));
+ Q_UNUSED(ux);
+ if (unk > 1) {
+ uint16_t unknown;
+ unknown = gbfgetuint16(fin);
+ DBG((sobj, "unknown value = 0x%04X (%d)\n", unknown, unknown));
+ Q_UNUSED(unknown);
+ }
+ }
+ track_add_wpt(trk, wpt);
+ }
+
+ if (mmo_version > 0) {
+ uint32_t u32 = gbfgetuint32(fin); /* Min. update interval */
+ DBG((sobj, "min. update interval = %d\n", u32));
+ u32 = gbfgetuint32(fin); /* unknown */
+ DBG((sobj, "unknown value = 0x%08X (%d)\n", u32, u32));
+ u32 = gbfgetuint32(fin); /* unknown */
+ DBG((sobj, "unknown value = 0x%08X (%d)\n", u32, u32));
+ u32 = gbfgetuint32(fin); /* unknown */
+ DBG((sobj, "min. update distance = %d\n", u32));
+ u32 = gbfgetuint32(fin); /* unknown */
+ DBG((sobj, "track partition interval = %d\n", u32 / 60));
+ u32 = gbfgetuint32(fin); /* unknown */
+ DBG((sobj, "unknown value = 0x%08X (%d)\n", u32, u32));
+ u32 = gbfgetuint32(fin); /* unknown */
+ DBG((sobj, "tick interval = %d\n", u32 / 60));
+ trk->line_color.bbggrr = gbfgetuint32(fin); /* rgb color */
+ trk->line_color.opacity = 255;
+ DBG((sobj, "color = 0x%06X\n", trk->line_color.bbggrr));
+ Q_UNUSED(u32);
+ }
+
+ if (mmo_version >= 0x12) {
+ char u8 = gbfgetc(fin);
+ DBG((sobj, "line width = %d - (since 0x12)\n", u8));
+ u8 = gbfgetc(fin);
+ DBG((sobj, "line style = %d - (since 0x12)\n", u8));
+ u8 = gbfgetc(fin);
+ DBG((sobj, "transparency = %d - (since 0x12)\n", u8));
+ trk->line_color.opacity = 255 - (u8 * 51);
+
+ if (mmo_version >= 0x16) {
+ // XXX ARB was u8 = gbfgetc(fin); but actually a string
+ // Don't construct a QString we aren't going to use.
+ // avoid clazy-unused-non-trivial-variable
+#ifdef MMO_DBG
+ QString text =
+#else
+ (void)
+#endif
+ mmo_readstr();
+ DBG((sobj, "text = \"%s\"\n", qPrintable(text)));
+ uint16_t u16 = gbfgetuint16(fin);
+ DBG((sobj, "unknown value = 0x%04X (since 0x16)\n", u16));
+ u16 = gbfgetuint16(fin);
+ DBG((sobj, "unknown value = 0x%04X (since 0x16)\n", u16));
+ Q_UNUSED(u16);
+ }
+ }
+
+ if (trk->rte_waypt_ct() == 0) {
+ track_del_head(trk);
+ data->data = nullptr;
+ }
+}
+
+
+static void
+mmo_read_CObjText(mmo_data_t*)
+{
+#ifdef MMO_DBG
+ const char* sobj = "CObjText";
+#endif
+ char buf[28];
+
+ DBG((sobj, ":-----------------------------------------------------\n"));
+ DBG((sobj, "name = \"%s\" [ visible=%s, id=0x%04X ]\n",
+ data->name, data->visible ? "yes" : "NO", data->objid));
+
+ double lat = gbfgetdbl(fin);
+ double lon = gbfgetdbl(fin);
+ DBG((sobj, "coordinates = %f / %f\n", lat, lon));
+ Q_UNUSED(lat);
+ Q_UNUSED(lon);
+
+ // Don't construct a QString we aren't going to use.
+ // avoid clazy-unused-non-trivial-variable
+#ifdef MMO_DBG
+ QString text =
+#else
+ (void)
+#endif
+ mmo_readstr();
+ DBG((sobj, "text = \"%s\"\n", qPrintable(text)));
+
+ mmo_fillbuf(buf, 28, 1);
+
+ // Don't construct a QString we aren't going to use.
+ // avoid clazy-unused-non-trivial-variable
+#ifdef MMO_DBG
+ QString font =
+#else
+ (void)
+#endif
+ mmo_readstr();
+ DBG((sobj, "font = \"%s\"\n", qPrintable(font)));
+
+ mmo_fillbuf(buf, 25, 1);
+}
+
+
+static void
+mmo_read_CObjCurrentPosition(mmo_data_t*)
+{
+#ifdef MMO_DBG
+ const char* sobj = "CObjCurrentPosition";
+#endif
+ char buf[24];
+
+ DBG((sobj, ":-----------------------------------------------------\n"));
+ DBG((sobj, "name = \"%s\" [ visible=%s, id=0x%04X ]\n",
+ data->name, data->visible ? "yes" : "NO", data->objid));
+
+ double lat = gbfgetdbl(fin);
+ double lon = gbfgetdbl(fin);
+ DBG((sobj, "coordinates = %f / %f\n", lat, lon));
+ Q_UNUSED(lat);
+ Q_UNUSED(lon);
+
+ mmo_fillbuf(buf, 24, 1);
+ if (mmo_version >= 0x18) {
+ mmo_fillbuf(buf, 8, 1); // XXX ARB read an extra 8
+ }
+
+ if (mmo_version >= 0x14) {
+ QString name = mmo_readstr();
+ DBG((sobj, "name = \"%s\"\n", qPrintable(name)));
+ // XXX ARB was just: mmo_fillbuf(buf, 13, 1);
+ // but actually it's string/long/string/long/long
+ (void) gbfgetuint32(fin);
+ name = mmo_readstr();
+ DBG((sobj, "name = \"%s\"\n", qPrintable(name)));
+ (void) gbfgetuint32(fin);
+ (void) gbfgetuint32(fin);
+ }
+}
+
+
+static mmo_data_t*
+mmo_read_object()
+{
+ mmo_data_t* data = nullptr;
+
+ // There are three cases:
+ // a new object of a type that has not occurred previously in this file;
+ // a new object; or
+ // a back reference to an object that appears earlier in the file.
+
+ int objid = gbfgetuint16(fin);
+ if (objid == 0xFFFF) {
+ DBG(("mmo_read_object", "Registering new object type\n"));
+
+ objid = mmo_object_id++;
+
+ uint16_t version = gbfgetuint16(fin);
+ if (version != mmo_version) {
+ fatal(MYNAME ": Invalid version identifier!\n");
+ }
+
+ int len = gbfgetint16(fin);
+
+ char* sobj = (char*) xmalloc(len + 1);
+ sobj[len] = '\0';
+ gbfread(sobj, len, 1, fin);
+ DBG(("mmo_read_object", "%s\n", sobj));
+
+ if (strcmp(sobj, "CObjIcons") == 0) {
+ ico_object_id = objid;
+ } else if (strcmp(sobj, "CCategory") == 0) {
+ cat_object_id = objid;
+ } else if (strcmp(sobj, "CObjWaypoint") == 0) {
+ wpt_object_id = objid;
+ } else if (strcmp(sobj, "CObjRoute") == 0) {
+ rte_object_id = objid;
+ } else if (strcmp(sobj, "CObjTrack") == 0) {
+ trk_object_id = objid;
+ } else if (strcmp(sobj, "CObjCurrentPosition") == 0) {
+ pos_object_id = objid;
+ } else if (strcmp(sobj, "CObjText") == 0) {
+ txt_object_id = objid;
+ } else {
+ fatal(MYNAME ": Unknown Object \"%s\"!\n", sobj);
+ }
+ xfree(sobj);
+ }
+
+ DBG(("mmo_read_object", "objid = 0x%04X\n", objid));
+
+ if (objid & 0x8000) {
+ data = mmo_register_object(mmo_object_id++, nullptr, (gpsdata_type)0);
+ data->name = xstrdup(mmo_readstr());
+
+ if (objid != cat_object_id) {
+ data->ctime = gbfgetuint32(fin);
+ data->mtime = gbfgetuint32(fin);
+ data->locked = gbfgetc(fin);
+ data->visible = gbfgetc(fin);
+
+ uint32_t obj_type = gbfgetuint32(fin);
+ (void) obj_type;
+#ifdef MMO_DBG
+ uint32_t expected_type = 0xFFFFFFFF;
+ if (objid == ico_object_id) {
+ expected_type = obj_type_ico;
+ } else if (objid == trk_object_id) {
+ expected_type = obj_type_trk;
+ } else if (objid == wpt_object_id) {
+ expected_type = obj_type_wpt;
+ } else if (objid == rte_object_id) {
+ expected_type = obj_type_rte;
+ } else if (objid == txt_object_id) {
+ expected_type = obj_type_txt;
+ }
+ if (mmo_version >= 0x18) {
+ expected_type <<= 24;
+ }
+ DBG(("mmo_read_object", "object type = 0x%08X\n", obj_type));
+ if (obj_type != expected_type) {
+ DBG(("mmo_read_object", " expected 0x%08X\n", expected_type));
+ }
+#endif
+
+ if (objid != ico_object_id) {
+ mmo_read_category(data);
+ }
+ DBG(("mmo_read_object", "Category : %s\n",
+ data->category ? data->category : "[No category]"));
+ }
+
+ if (objid == cat_object_id) ; /* do nothing */
+ else if (objid == ico_object_id) {
+ mmo_read_CObjIcons(data);
+ } else if (objid == trk_object_id) {
+ data->type = trkdata;
+ mmo_read_CObjTrack(data);
+ } else if (objid == wpt_object_id) {
+ data->type = wptdata;
+ mmo_read_CObjWaypoint(data);
+ } else if (objid == rte_object_id) {
+ data->type = rtedata;
+ mmo_read_CObjRoute(data);
+ } else if (objid == pos_object_id) {
+ mmo_read_CObjCurrentPosition(data);
+ } else if (objid == txt_object_id) {
+ mmo_read_CObjText(data);
+ } else {
+ fatal(MYNAME ": Unregistered Object-ID 0x%04X\n", objid);
+ }
+ } else {
+ data = mmo_get_object(objid);
+ }
+
+ return data;
+}
+
+static void
+mmo_finalize_rtept_cb(const Waypoint* wptref)
+{
+ auto* wpt = const_cast<Waypoint*>(wptref);
+
+ if ((wpt->shortname[0] == '\01') && (wpt->latitude == 0) && (wpt->longitude == 0)) {
+ mmo_data_t* data;
+ Waypoint* wpt2;
+
+// This code path isn't tested in anything we have and I have No Idea
+// what it was trying to do. Throw a hard error to force the hand of
+// getting a sample file.
+ abort();
+#if OLD
+ sscanf(wpt->shortname + 1, "%p", &data);
+#endif
+ wpt2 = (Waypoint*)data->data;
+
+ wpt->latitude = wpt2->latitude;
+ wpt->longitude = wpt2->longitude;
+ wpt->shortname = wpt2->shortname;
+
+ wpt->description = wpt2->description;
+ wpt->notes = (wpt2->notes);
+ if (wpt2->HasUrlLink()) {
+ UrlLink l = wpt2->GetUrlLink();
+ wpt->notes = l.url_;
+ }
+
+ wpt->proximity = wpt2->proximity;
+ wpt->wpt_flags.proximity = wpt2->wpt_flags.proximity;
+
+ if (!wpt2->icon_descr.isNull()) {
+ wpt->icon_descr = wpt2->icon_descr;
+ }
+ }
+}
+
+/*******************************************************************************
+* %%% global callbacks called by gpsbabel main process %%% *
+*******************************************************************************/
+
+static void
+mmo_rd_init(const QString& fname)
+{
+ fin = gbfopen_le(fname, "rb", MYNAME);
+
+ utf16le_codec = QTextCodec::codecForName("UTF-16LE");
+ legacy_codec = QTextCodec::codecForName("Windows-1252");
+
+ ico_object_id = pos_object_id = txt_object_id = cat_object_id = 0;
+ wpt_object_id = rte_object_id = trk_object_id = 0;
+
+ mmo_object_id = 0x8001;
+
+ int i = 0;
+ while (mmo_icon_value_table[i].icon) {
+ mmo_register_icon(mmo_icon_value_table[i].value, mmo_icon_value_table[i].icon);
+ i++;
+ }
+}
+
+
+static void
+mmo_rd_deinit()
+{
+ route_disp_session(curr_session(), nullptr, nullptr, mmo_finalize_rtept_cb);
+
+ icons.clear();
+
+ for (auto* value : qAsConst(objects)) {
+ mmo_free_object(value);
+ }
+ objects.clear();
+
+ legacy_codec = nullptr;
+ utf16le_codec = nullptr;
+
+ gbfclose(fin);
+}
+
+
+static void
+mmo_read()
+{
+#ifdef MMO_DBG
+ const char* sobj = "main";
+#endif
+
+ /* copy file to memory stream (needed for seek-ops and piped commands) */
+
+ DBG(("main", "loading file \"%s\".\n", fin->name));
+
+ gbfile* fx = gbfopen(nullptr, "wb", MYNAME);
+ gbfcopyfrom(fx, fin, 0x7FFFFFFF);
+ gbfrewind(fx);
+ gbfclose(fin);
+ fin = fx;
+
+ mmo_obj_ct = gbfgetuint16(fin);
+ DBG((sobj, "number of objects = %d\n", mmo_obj_ct));
+
+ int i = gbfgetuint16(fin);
+ if (i != 0xFFFF) {
+ fatal(MYNAME ": Marker not equal to 0xFFFF!\n");
+ }
+
+ mmo_version = gbfgetuint16(fin);
+ DBG((sobj, "version = 0x%02X\n", mmo_version));
+
+ mmo_filemark = 0xFFFF0000UL | be_read16(&mmo_version);
+ DBG((sobj, "filemark = 0x%08X\n", mmo_filemark));
+
+ gbfseek(fin, -4, SEEK_CUR);
+
+ while (! gbfeof(fin)) { /* main read loop */
+
+ (void) mmo_read_object();
+
+ }
+
+#ifdef MMO_DBG
+ printf("\n" MYNAME ":---------------------------------------\n");
+ printf(MYNAME ": EOF reached, nice!!!\n");
+ printf(MYNAME ": =======================================\n\n");
+#endif
+}
+
+/**************************************************************************/
+
+static void
+mmo_register_category_names(const QString& name)
+{
+ category_names.insert(name, mmo_object_id);
+}
+
+
+static void
+mmo_writestr(const QString& str)
+{
+
+ bool topbitset = false;
+
+ // see if there's any utf-8 multi-byte chars
+ const QByteArray utf8 = str.toUtf8();
+ int len = utf8.size();
+ for (unsigned char byte : utf8) {
+ if (byte & 0x80) {
+ topbitset = true;
+ break;
+ }
+ }
+ // Old version can't handle utf-16
+ // XXX ARB check which version number can, just guessed at 0x12
+ if (mmo_version < 0x12) {
+ topbitset = false;
+ }
+
+ QByteArray outbytes;
+ if (topbitset) {
+ // Use an encoder to avoid generating a BOM.
+ QScopedPointer<QTextEncoder> encoder(utf16le_codec->makeEncoder(QTextCodec::IgnoreHeader));
+ outbytes = encoder->fromUnicode(str);
+ assert(outbytes.size() % 2 == 0);
+ len = outbytes.size() / 2;
+ len = len & 0xff;
+ } else {
+ outbytes = legacy_codec->fromUnicode(str);
+ len = outbytes.size();
+ }
+
+ // XXX ARB need to convert UTF-8 into UTF-16
+ if (topbitset) {
+ gbfputc(0xFF, fout); // means two-byte length follows
+ gbfputc(0xFE, fout); // means utf-16 little-endian string follows
+ gbfputc(0xFF, fout); // ditto
+ gbfputc(len, fout);
+ } else if (len > 254) {
+ len = len & 0x7FFF;
+ gbfputc(0xFF, fout); // means two-byte length follows
+ gbfputint16(len, fout);
+ } else {
+ gbfputc(len, fout);
+ }
+ if (len) {
+ if (topbitset) {
+ gbfwrite(outbytes, 1, len*2, fout);
+ } else {
+ gbfwrite(outbytes, 1, len, fout);
+ }
+ }
+}
+
+static void
+mmo_enum_waypt_cb(const Waypoint*)
+{
+ mmo_obj_ct++;
+}
+
+
+static void
+mmo_enum_route_cb(const route_head* rte)
+{
+ if (rte->rte_waypt_ct() > 0) {
+ mmo_obj_ct++;
+ }
+}
+
+
+static int
+mmo_write_obj_mark(const char* sobj, const char* name)
+{
+ QString key = QString::fromUtf8(sobj);
+
+ if (mmobjects.contains(key)) {
+ uint16_t nr = mmobjects.value(key);
+ gbfputuint16(nr, fout);
+ } else {
+ mmo_object_id++;
+
+ DBG(("write", "object \"%s\", registered type \"%s\" (id = 0x%04X)\n",
+ name, sobj, mmo_object_id));
+
+ mmobjects.insert(key, mmo_object_id);
+
+ gbfputuint32(mmo_filemark, fout);
+ gbfputuint16(strlen(sobj), fout);
+ gbfwrite(sobj, strlen(sobj), 1, fout);
+ }
+
+ mmo_object_id++;
+ int res = mmo_object_id;
+ mmo_writestr(name);
+
+ return res;
+}
+
+
+static void
+mmo_write_category(const char* sobj, const char* name)
+{
+ QString key = QString::fromUtf8(name);
+
+ if (category_names.contains(key)) {
+ uint16_t nr = category_names.value(key);
+ gbfputuint16(nr & 0x7FFF, fout);
+ } else {
+ mmo_write_obj_mark(sobj, name);
+ mmo_register_category_names(key);
+ }
+}
+
+
+static int
+mmo_write_obj_head(const char* sobj, const char* name, const time_t ctime,
+ const uint32_t obj_type)
+{
+ int res = mmo_write_obj_mark(sobj, name);
+
+ gbfputuint32(ctime, fout);
+ gbfputuint32(ctime, fout);
+
+ gbfputc(*opt_locked, fout);
+ gbfputc(*opt_visible, fout);
+
+ gbfputuint32(obj_type, fout);
+
+ return res;
+}
+
+
+static void
+mmo_write_wpt_cb(const Waypoint* wpt)
+{
+ QString str;
+ int icon = 0;
+
+ time_t time = wpt->GetCreationTime().toTime_t();
+ if (time < 0) {
+ time = 0;
+ }
+
+ if (mmo_datatype == trkdata) {
+ gbfputdbl(wpt->latitude, fout);
+ gbfputdbl(wpt->longitude, fout);
+ gbfputc(0, fout);
+ gbfputuint32(time, fout);
+ if (wpt->altitude != unknown_alt) {
+ gbfputflt(wpt->altitude, fout);
+ } else {
+ gbfputflt(0, fout);
+ }
+
+ return;
+ }
+
+ DBG(("write", "waypoint \"%s\"\n", wpt->shortname ? wpt->shortname : "Mark"));
+ int objid = mmo_write_obj_head("CObjWaypoint",
+ wpt->shortname.isEmpty() ? "Mark" : CSTR(wpt->shortname), time, obj_type_wpt);
+ mmo_data_t* data = mmo_register_object(objid, wpt, wptdata);
+ data->refct = 1;
+ mmo_write_category("CCategory", (mmo_datatype == rtedata) ? "Waypoints" : "Marks");
+
+ gbfputdbl(wpt->latitude, fout);
+ gbfputdbl(wpt->longitude, fout);
+
+ if (mmo_datatype == rtedata) {
+ int i = mmo_get_objid(mmo_rte);
+ gbfputuint16(1, fout); /* two extra bytes */
+ gbfputuint16(i & 0x7FFF, fout);
+ } else {
+ gbfputuint16(0, fout); /* extra bytes */
+ }
+
+ if (wpt->HasUrlLink()) {
+ str = "_FILE_ ";
+ UrlLink l = wpt->GetUrlLink();
+ str += l.url_;
+ str += "\n";
+ }
+
+ QString cx = wpt->notes;
+ if (cx == nullptr) {
+ cx = wpt->description;
+ }
+ if (cx != nullptr) {
+ char* kml = nullptr;
+
+ if (wpt->session->name == QLatin1String("kml")) {
+ utf_string tmp(true, cx);
+ cx = kml = strip_html(&tmp);
+ }
+ str += cx;
+ if (kml) {
+ xfree(kml);
+ }
+ }
+ mmo_writestr(str);
+
+ gbfputuint32(0x01, fout);
+ if WAYPT_HAS(wpt, proximity) {
+ gbfputflt((int) wpt->proximity, fout);
+ } else {
+ gbfputflt(0, fout);
+ }
+
+ if (!wpt->icon_descr.isNull()) {
+ int i = 0;
+
+ while (mmo_icon_value_table[i].icon) {
+ if (wpt->icon_descr.compare(mmo_icon_value_table[i].icon, Qt::CaseInsensitive) == 0) {
+ icon = mmo_icon_value_table[i].value;
+ break;
+ }
+ i++;
+ }
+ }
+ gbfputuint32(icon, fout);
+
+ mmo_writestr(""); /* name on gps */
+ gbfputuint32(0x00, fout);
+}
+
+
+static void
+mmo_write_rte_head_cb(const route_head* rte)
+{
+ time_t time = 0x7FFFFFFF;
+
+ if (rte->rte_waypt_ct() <= 0) {
+ return;
+ }
+
+ mmo_rte = rte;
+
+ foreach (const Waypoint* wpt, rte->waypoint_list) {
+ gpsbabel::DateTime t = wpt->GetCreationTime();
+ if ((t.isValid()) && (t.toTime_t() < time)) {
+ time = t.toTime_t();
+ }
+ }
+ if (time == 0x7FFFFFFF) {
+ time = gpsbabel_time;
+ }
+ int objid = mmo_write_obj_head("CObjRoute",
+ rte->rte_name.isEmpty() ? "Route" : CSTR(rte->rte_name), time, obj_type_rte);
+ mmo_register_object(objid, rte, rtedata);
+ mmo_write_category("CCategory", "Route");
+ gbfputc(0, fout); /* unknown */
+ gbfputuint16(rte->rte_waypt_ct(), fout);
+}
+
+
+static void
+mmo_write_rte_tail_cb(const route_head* rte)
+{
+ if (rte->rte_waypt_ct() <= 0) {
+ return;
+ }
+
+ DBG(("write", "route with %d point(s).\n", rte->rte_waypt_ct()));
+
+ if (mmo_version >= 0x12) {
+ if (rte->line_color.bbggrr < 0) {
+ gbfputuint32(0xFF, fout); /* color; default red */
+ gbfputc(0x01, fout); /* Line width "normal" */
+ gbfputc(0x00, fout); /* Line style "solid"*/
+ gbfputc(0x00, fout); /* Transparency "Opaque" */
+ } else {
+ gbfputuint32(rte->line_color.bbggrr, fout); /* color */
+ gbfputc(0x01, fout); /* Line width "normal" */
+ gbfputc(0x00, fout); /* Line style "solid"*/
+ gbfputc((255 - rte->line_color.opacity) / 51, fout); /* Transparency "Opaque" */
+ }
+ }
+
+ foreach (const Waypoint* wpt, rte->waypoint_list) {
+ int objid = mmo_get_objid(wpt);
+ gbfputuint16(objid & 0x7FFF, fout);
+ }
+}
+
+
+static void
+mmo_write_trk_head_cb(const route_head* trk)
+{
+ if (trk->rte_waypt_ct() <= 0) {
+ return;
+ }
+ int objid = mmo_write_obj_head("CObjTrack",
+ trk->rte_name.isEmpty() ? "Track" : CSTR(trk->rte_name), gpsbabel_time, obj_type_trk);
+
+ mmo_write_category("CCategory", "Track");
+ gbfputuint16(trk->rte_waypt_ct(), fout);
+
+ mmo_register_object(objid, trk, trkdata);
+}
+
+
+static void
+mmo_write_trk_tail_cb(const route_head* trk)
+{
+ if (trk->rte_waypt_ct() <= 0) {
+ return;
+ }
+
+ gbfputuint32(0x0A, fout); /* Min. update interval */
+ gbfputflt(0, fout);
+ gbfputflt(0, fout);
+ gbfputuint32(0x0F, fout); /* Min. update distance */
+ gbfputuint32(0xE10, fout); /* Track partition interval */
+ gbfputuint32(0x00, fout); /* ??? */
+ gbfputuint32(0x12C, fout);
+
+ if (trk->line_color.bbggrr < 0) {
+ gbfputuint32(0xFF0000, fout); /* color; default blue */
+ if (mmo_version >= 0x12) {
+ gbfputc(0x01, fout); /* Line width "normal" */
+ gbfputc(0x00, fout); /* Line style "solid"*/
+ gbfputc(0x00, fout); /* Transparency "Opaque" */
+ }
+ } else {
+ gbfputuint32(trk->line_color.bbggrr, fout); /* color */
+ if (mmo_version >= 0x12) {
+ gbfputc(0x01, fout); /* Line width "normal" */
+ gbfputc(0x00, fout); /* Line style "solid"*/
+ gbfputc((255 - trk->line_color.opacity) / 51, fout); /* Transparency "Opaque" */
+ }
+ }
+}
+
+/**************************************************************************/
+
+static void
+mmo_wr_init(const QString& fname)
+{
+ fout = gbfopen_le(fname, "wb", MYNAME);
+
+ utf16le_codec = QTextCodec::codecForName("UTF-16LE");
+ legacy_codec = QTextCodec::codecForName("Windows-1252");
+
+ mmo_object_id = 0x8000;
+ mmo_obj_ct = 1; /* ObjIcons always present */
+ mmo_version = 0x12; /* by default we write as version 0x12 */
+ if (opt_version) {
+ while (isspace(*opt_version)) {
+ opt_version++;
+ }
+ errno = 0;
+ mmo_version = strtol(opt_version, nullptr, 0);
+ if (errno || ((mmo_version != 0x11) && (mmo_version != 0x12))) {
+ fatal(MYNAME ": Unsupported version identifier (%s)!\n", opt_version);
+ }
+ }
+ DBG(("write", "version = 0x%02X\n", mmo_version));
+ mmo_filemark = 0xFFFFUL | (mmo_version << 16);
+}
+
+
+static void
+mmo_wr_deinit()
+{
+ mmobjects.clear();
+ category_names.clear();
+
+ for (auto* value : qAsConst(objects)) {
+ mmo_free_object(value);
+ }
+ objects.clear();
+
+ legacy_codec = nullptr;
+ utf16le_codec = nullptr;
+
+ gbfclose(fout);
+}
+
+
+static void
+mmo_write()
+{
+ /* find out number of objects we have to write */
+ waypt_disp_all(mmo_enum_waypt_cb);
+ route_disp_all(mmo_enum_route_cb, nullptr, mmo_enum_waypt_cb);
+ track_disp_all(mmo_enum_route_cb, nullptr, nullptr);
+
+ gbfputuint16(mmo_obj_ct, fout);
+
+ mmo_write_obj_head("CObjIcons", "Unnamed object", gpsbabel_time, obj_type_ico);
+ for (int i = 0; i < 5; i++) {
+ gbfputuint16(0, fout);
+ }
+
+ mmo_datatype = wptdata;
+ waypt_disp_all(mmo_write_wpt_cb);
+ mmo_datatype = rtedata;
+ route_disp_all(mmo_write_rte_head_cb, mmo_write_rte_tail_cb, mmo_write_wpt_cb);
+ mmo_datatype = trkdata;
+ track_disp_all(mmo_write_trk_head_cb, mmo_write_trk_tail_cb, mmo_write_wpt_cb);
+}
+
+/**************************************************************************/
+
+ff_vecs_t mmo_vecs = {
+ ff_type_file,
+ FF_CAP_RW_ALL, /* read and write waypoints, tracks and routes*/
+ mmo_rd_init,
+ mmo_wr_init,
+ mmo_rd_deinit,
+ mmo_wr_deinit,
+ mmo_read,
+ mmo_write,
+ nullptr,
+ &mmo_args,
+ CET_CHARSET_MS_ANSI, 0
+ , NULL_POS_OPS
+};
+
+/**************************************************************************/
--- /dev/null
+/*
+
+Format converter for MediaTek Locus-capable devices.
+
+Copyright (C) 2012 Jeremy Mortis, mortis@tansay.ca
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+-------------------------------------------------------------------
+
+This module will download logged track data (a.k.a. Locus) from a GPS
+devices based on the MediaTek MT3339 GPS chipset, such as:
+- GlobalTop PA6H Module
+- Fastrax IT530
+
+The MT3339 also emits standard NMEA packets including
+$GPGGA, $GPGSA, $GPGSV, $GPRMC, and $GPVTG. This module ignores those.
+If you have an MT3339 and you want to process NMEA packets, simply use
+the nmea format instead of this one.
+
+Example usage::
+# Read from USB port, output trackpoints in GPX format
+./gpsbabel -t -i mtk_locus -f /dev/ttyUSB0 -o gpx -F out.gpx
+
+*/
+
+
+#include "defs.h"
+#include "gbser.h"
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+
+static route_head* track;
+
+static char* opt_baudrate;
+static char* opt_download;
+static char* opt_erase;
+static char* opt_status;
+static char* opt_enable;
+
+static QVector<arglist_t> mtk_locus_args = {
+ {"baudrate", &opt_baudrate, "Speed in bits per second of serial port (autodetect=0)", "0", ARGTYPE_INT, ARG_NOMINMAX , nullptr},
+ {"download", &opt_download, "Download logged fixes", "1", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr },
+ {"erase", &opt_erase, "Erase device data after download", "0", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr },
+ {"status", &opt_status, "Show device status", "0", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr },
+ {"enable", &opt_enable, "Enable logging after download", "0", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr },
+};
+
+static void mtk_locus_rd_init(const QString& fname);
+static void mtk_locus_rd_deinit();
+static void mtk_locus_read();
+
+ff_vecs_t mtk_locus_vecs = {
+ ff_type_file,
+ {
+ ff_cap_read /* waypoints */,
+ ff_cap_read /* tracks */,
+ ff_cap_none /* routes */
+ },
+ mtk_locus_rd_init,
+ nullptr, // write init
+ mtk_locus_rd_deinit,
+ nullptr, // write deinit
+ mtk_locus_read,
+ nullptr, // write
+ nullptr, // exit
+ &mtk_locus_args,
+ CET_CHARSET_ASCII, 0 /* ascii is the expected character set */
+ , NULL_POS_OPS
+};
+
+#define MYNAME "mtk_locus"
+#define TIMEOUT 1500
+
+#define PMTK_ACK "$PMTK001"
+#define PMTK_LOCUS_STOP_LOGGER "$PMTK185"
+#define PMTK_LOCUS_QUERY_STATUS "$PMTK183"
+#define PMTK_LOCUS_ERASE_FLASH "$PMTK184"
+#define PMTK_Q_LOCUS_DATA "$PMTK622"
+#define PMTK_Q_RELEASE "$PMTK605"
+#define PMTK_DT_RELEASE "$PMTK705"
+
+static gbfile* ffd; // File access.
+static void* sfd;
+static enum {rm_serial, rm_file} read_mode;
+static int packetnum;
+static char line[1000];
+static int download_complete;
+static int valid_packet_found;
+static int fixes_found;
+static int first_loxsequence;
+static int last_loxsequence;
+static char waiting_for[20];
+
+
+static void set_baudrate();
+static void read_line();
+static void process_packet();
+static void process_pmtklox();
+static void process_pmtklog();
+static void process_pmtk001();
+static void process_pmtk705();
+static void send_command(const char* s, const char*wait_for);
+static int calculate_checksum(const char* s, int length);
+static void dbg(int l, const char* msg, ...);
+
+static void
+mtk_locus_rd_init(const QString& fname)
+{
+ dbg(1, "Opening file: %s\n", qPrintable(fname));
+
+ if (gbser_is_serial(qPrintable(fname))) {
+
+ dbg(1, "Input is a serial port\n");
+ read_mode = rm_serial;
+ if ((sfd = gbser_init(qPrintable(fname))) == nullptr) {
+ fatal(MYNAME ": Can't initialise port \"%s\" (%s)\n", qPrintable(fname), strerror(errno));
+ }
+ set_baudrate();
+ gbser_flush(sfd);
+
+ } else {
+
+ dbg(1, "Input is a normal file\n");
+ read_mode = rm_file;
+ if ((ffd = gbfopen(fname, "rb", MYNAME)) == nullptr) {
+ fatal(MYNAME ": Can't initialise port \"%s\" (%s)\n", qPrintable(fname), strerror(errno));
+ }
+ }
+
+ dbg(1, "File opened\n");
+}
+
+static void
+mtk_locus_rd_deinit()
+{
+ if (read_mode == rm_serial) {
+ gbser_deinit(sfd);
+ } else {
+ gbfclose(ffd);
+ }
+}
+
+static void
+mtk_locus_read()
+{
+ track = new route_head;
+ track_add_head(track);
+ dbg(1, "Track initialized\n");
+
+ packetnum = 0;
+ valid_packet_found = 0;
+ fixes_found = 0;
+ download_complete = 0;
+ first_loxsequence = -1;
+ last_loxsequence = -1;
+
+ read_line();
+ // initial serial buffer may contain garbage, so read until valid packet found
+ for (int i = 0; i<10; i++) {
+ process_packet();
+ read_line();
+ if (valid_packet_found) {
+ break;
+ }
+ }
+
+ if (! valid_packet_found) {
+ fatal(MYNAME "No valid input data found");
+ }
+
+ if (strcmp(opt_download, "1") == 0) {
+ send_command(PMTK_Q_LOCUS_DATA ",1", nullptr);
+
+ while (! download_complete) {
+ process_packet();
+ read_line();
+ }
+ }
+
+ if (read_mode == rm_serial) {
+ if (strcmp(opt_erase, "1") == 0) {
+ send_command(PMTK_LOCUS_ERASE_FLASH ",1", PMTK_ACK);
+ printf("Flash erased\n");
+ }
+
+ if (strcmp(opt_enable, "1") == 0) {
+ send_command(PMTK_LOCUS_STOP_LOGGER ",0", PMTK_ACK);
+ printf("Logging enabled\n");
+ } else {
+ send_command(PMTK_LOCUS_STOP_LOGGER ",1", PMTK_ACK);
+ printf("Logging disabled\n");
+ }
+
+ if (strcmp(opt_status, "1") == 0) {
+ printf("Device status:\n");
+ send_command(PMTK_Q_RELEASE, PMTK_DT_RELEASE);
+ send_command(PMTK_LOCUS_QUERY_STATUS, PMTK_ACK);
+ }
+ }
+}
+
+void
+set_baudrate()
+{
+ int rc;
+ int baudrates[] = { 4800, 9600, 14400, 19200, 38400, 57600, 115200, 0 };
+ int baudrate;
+
+ if (strcmp(opt_baudrate, "0") != 0) {
+
+ baudrate = atoi(opt_baudrate);
+ rc = gbser_set_speed(sfd, baudrate);
+ if (rc != gbser_OK) {
+ fatal(MYNAME ": Set baud rate to %i failed (%i)\n", baudrate, rc);
+ }
+
+ } else {
+
+ dbg(1, "Probing for baudrate...\n");
+ for (int i=0;; i++) {
+ baudrate = baudrates[i];
+ if (baudrate == 0) {
+ fatal(MYNAME ": Autobaud connection failed\n");
+ }
+ dbg(1, MYNAME ": Probing at %i baud...\n", baudrate);
+ rc = gbser_set_speed(sfd, baudrate);
+
+ if (rc != gbser_OK) {
+ dbg(1, "Set speed failed\n");
+ continue;
+ }
+
+ rc = gbser_read_line(sfd, line, sizeof(line)-1, TIMEOUT, 0x0A, 0x0D);
+ if (rc != gbser_OK) {
+ dbg(1, "Read test failed\n");
+ continue;
+ }
+
+ dbg(1, "Port successfully opened\n");
+ break;
+ }
+ }
+}
+
+void
+read_line()
+{
+ line[0] = '\0';
+
+ if (read_mode == rm_file) {
+ char* s = gbfgetstr(ffd);
+ if (s == nullptr) {
+ dbg(1, "EOF reached\n");
+ download_complete = 1;
+ return;
+ }
+ strncat(line, s, sizeof(line)-1);
+ } else {
+ int rc = gbser_read_line(sfd, line, sizeof(line)-1, TIMEOUT, 0x0A, 0x0D);
+ if (rc != gbser_OK) {
+ fatal(MYNAME "Serial read failed: %i\n", rc);
+ }
+ }
+
+ packetnum++;
+ dbg(1, "Line %i: %s\n", packetnum, line);
+}
+
+void
+process_packet()
+{
+ int given_checksum;
+
+ if ((strlen(line) < 3) || (line[0] != '$') || (line[strlen(line)-3] != '*')) {
+ dbg(1, "Line %i: Malformed packet\n", packetnum);
+ return;
+ }
+
+ int calculated_checksum = calculate_checksum(&line[1], strlen(line) - 1 - 3);
+ sscanf(&line[strlen(line) - 2], "%02x", &given_checksum);
+ if (calculated_checksum != given_checksum) {
+ dbg(1, "Line %i: NMEA Checksum incorrect, expecting %02X\n", packetnum, calculated_checksum);
+ return;
+ }
+
+ if (strncmp(line, waiting_for, strlen(waiting_for)) == 0) {
+ waiting_for[0] = '\0';
+ }
+
+ valid_packet_found = 1;
+ line[strlen(line) - 3] = '\0'; // remove checksum
+
+ // note that use of strtok in following routines corrupts the value of line
+
+ if (strncmp(line, "$PMTKLOX", 8) == 0) {
+ process_pmtklox();
+ } else if (strncmp(line, "$PMTKLOG", 8) == 0) {
+ process_pmtklog();
+ } else if (strncmp(line, "$PMTK001", 8) == 0) {
+ process_pmtk001();
+ } else if (strncmp(line, "$PMTK705", 8) == 0) {
+ process_pmtk705();
+ } else {
+ dbg(1, "Unknown packet type\n");
+ }
+
+}
+
+void
+process_pmtklox()
+{
+ uint8_t fixbytes[16];
+ static Waypoint* trkpt;
+ static Waypoint* waypt;
+
+ char* token = strtok(line, ",");
+ if ((token == nullptr) || (strcmp(token, "$PMTKLOX") != 0)) {
+ warning("Line %i: Invalid packet id\n", packetnum);
+ return;
+ }
+
+ char* loxtype = strtok(nullptr, ",");
+ if (loxtype == nullptr) {
+ warning("Line %i: Missing lox type\n", packetnum);
+ return;
+ }
+
+ if (strcmp(loxtype, "0") == 0) {
+ last_loxsequence = atoi(strtok(nullptr, "*")) - 1;
+ dbg(1, "Line %i: last sequence will be %i\n", packetnum, last_loxsequence);
+ return;
+ }
+
+ if (strcmp(loxtype, "2") == 0) {
+ printf("Found %i fixes\n", fixes_found);
+ download_complete = 1;
+ return;
+ }
+
+ if (strcmp(loxtype, "1") != 0) {
+ dbg(1, "Line %i: Invalid lox type\n", packetnum);
+ return;
+ }
+
+ int loxsequence = atoi(strtok(nullptr, ","));
+
+ if (first_loxsequence == -1) {
+ first_loxsequence = loxsequence;
+ if (first_loxsequence != 0) {
+ fatal(MYNAME "Dump already in progress (first $PMTKLOX has sequence %i)\n", first_loxsequence);
+ }
+ }
+
+ if (read_mode == rm_serial) {
+ printf("Downloading packet %i of %i\r", loxsequence, last_loxsequence);
+ }
+
+ token = strtok(nullptr, ",");
+ int fixnum = 0;
+ while (token != nullptr) {
+ fixnum++;
+ int bytenum = 0;
+ uint8_t calculated_checksum = 0;
+ for (int wordnum = 0; wordnum<4; wordnum++) { // 4 8-byte hex strings per fix
+ if (token == nullptr) {
+ dbg(1, "Line %i: Fix %i incomplete data\n", packetnum, fixnum);
+ return;
+ }
+ for (int i = 0; i<4; i++) {
+ unsigned int hexval;
+ sscanf(&token[i * 2], "%2x", &hexval);
+ fixbytes[bytenum++] = hexval;
+ calculated_checksum ^= hexval;
+ }
+ token = strtok(nullptr, ",");
+ }
+
+ if (calculated_checksum != 0) {
+ dbg(1, "Line %i: Fix %i failed checksum\n", packetnum, fixnum);
+ continue;
+ }
+
+ uint32_t timestamp = le_read32(&fixbytes[0]);
+ char fixtype = fixbytes[4];
+ float latitude = le_read_float(&fixbytes[5]);
+ float longitude = le_read_float(&fixbytes[9]);
+ int height = le_read16(&fixbytes[13]);
+
+ if (fixtype != '\x02') {
+ dbg(1, "line %i: Fix %i Invalid fix type: %02X\n", packetnum, fixnum, fixtype);
+ continue;
+ }
+
+ if ((latitude < -180.0) || (latitude > 180.0)
+ || (longitude < -180.0) || (longitude > 180.0)
+ || (height < -1000) || (height > 100000)) {
+ dbg(1, "line %i: Fix %i data out of range\n", packetnum, fixnum);
+ continue;
+ }
+
+ if (global_opts.masked_objective & TRKDATAMASK) {
+ trkpt = new Waypoint;
+ trkpt->SetCreationTime(timestamp);
+ trkpt->latitude = latitude;
+ trkpt->longitude = longitude;
+ trkpt->altitude = height;
+ trkpt->sat = 0;
+ trkpt->hdop = 0;
+ trkpt->fix = fix_3d;
+ track_add_wpt(track, trkpt);
+ }
+
+ if (global_opts.masked_objective & WPTDATAMASK) {
+ waypt = new Waypoint;
+ waypt->SetCreationTime(timestamp);
+ waypt->latitude = latitude;
+ waypt->longitude = longitude;
+ waypt->altitude = height;
+ waypt->sat = 0;
+ waypt->hdop = 0;
+ waypt->fix = fix_3d;
+ waypt_add(waypt);
+ }
+
+ dbg(1, "Time: %li Type: %02x Lat: %f Long: %f height: %i\n", (long int)timestamp, fixtype, latitude, longitude, height);
+
+ fixes_found++;
+ }
+}
+
+void
+process_pmtklog()
+{
+ strtok(line, ",");
+
+ printf("Serial#: %s\n", strtok(nullptr, ","));
+
+ int type = atoi(strtok(nullptr, ","));
+ if (type == 0) {
+ printf("Type: %i (wrap around when full)\n", type);
+ } else {
+ printf("Type: %i (stop when full)\n", type);
+ }
+
+ printf("Mode: 0x%02X\n", atoi(strtok(nullptr, ",")));
+ printf("Content: %s\n", strtok(nullptr, ","));
+ printf("Interval: %s seconds\n", strtok(nullptr, ","));
+ printf("Distance: %s\n", strtok(nullptr, ","));
+ printf("Speed: %s\n", strtok(nullptr, ","));
+
+ int status = atoi(strtok(nullptr, ","));
+ if (status == 0) {
+ printf("Status: %i (enabled)\n", status);
+ } else {
+ printf("Status: %i (disabled)\n", status);
+ }
+
+ printf("Number: %s fixes available\n", strtok(nullptr, ","));
+ printf("Percent: %s%% used\n", strtok(nullptr, ","));
+}
+
+void
+process_pmtk001()
+{
+ strtok(line, ",");
+ char* cmd = strtok(nullptr,",");
+ char* flag = strtok(nullptr,",");
+
+ switch (atoi(flag)) {
+ case 0:
+ dbg(1, "Ack: %s %s (Invalid command)\n", cmd, flag);
+ break;
+ case 1:
+ dbg(1, "Ack: %s %s (Unsupported command)\n", cmd, flag);
+ break;
+ case 2:
+ dbg(1, "Ack: %s %s (Action failed)\n", cmd, flag);
+ break;
+ case 3:
+ dbg(1, "Ack: %s %s (Success)\n", cmd, flag);
+ break;
+ default:
+ dbg(1, "Ack: %s %s (Unknown error)\n", cmd, flag);
+ break;
+ }
+}
+
+void
+process_pmtk705()
+{
+ char* token = strtok(line, ",");
+ token = strtok(nullptr,",");
+
+ printf("Firmware: %s\n", token);
+}
+
+void
+send_command(const char* s, const char* wait_for)
+{
+ time_t starttime;
+ time_t currtime;
+ char cmd[100];
+
+ if (read_mode == rm_file) {
+ dbg(1, "Sending device commands ignored when using file input: %s\n", s);
+ return;
+ }
+
+ int checksum = calculate_checksum(&s[1], strlen(s)-1);
+ snprintf(cmd, sizeof(cmd)-1, "%s*%02X\r\n", s, checksum);
+
+ int rc = gbser_print(sfd, cmd);
+ if (rc != gbser_OK) {
+ fatal(MYNAME ": Write error (%d)\n", rc);
+ }
+
+ dbg(1, "Sent command: %s\n", cmd);
+
+ if (wait_for == nullptr) {
+ waiting_for[0] = '\0';
+ return;
+ }
+
+ time(&starttime);
+ cmd[0] = '\0';
+ strncat(cmd, &s[5], 3);
+ waiting_for[0] = '\0';
+ strncat(waiting_for, wait_for, sizeof(waiting_for)-1);
+ dbg(1, "Waiting for: %s\n", waiting_for);
+
+ read_line();
+ while (strlen(waiting_for) > 0) {
+ time(&currtime);
+ if (currtime > starttime + 5) {
+ fatal(MYNAME "Ack not received: %s\n", s);
+ }
+ process_packet();
+ read_line();
+ }
+}
+
+int
+calculate_checksum(const char* s, int length)
+{
+ int sum = 0;
+
+ for (int i = 0; i<length; i++) {
+ sum ^= *s++;
+ }
+ return sum;
+}
+
+void
+dbg(int l, const char* msg, ...)
+{
+ va_list ap;
+ va_start(ap, msg);
+ if (global_opts.debug_level >= l) {
+ vfprintf(stderr,msg, ap);
+ fflush(stderr);
+ }
+ va_end(ap);
+}
+
+
--- /dev/null
+/*
+ Handle MyNav TRC format .trc and .ftn files
+
+ For information on the data format see
+ http://www.mynav.it/hwdoc/dev/TRC_Format_Spec.pdf
+
+ Copyright (c) 2014-2020 Ralf Horstmann <ralf@ackstorm.de>
+ Copyright (C) 2014-2020 Robert Lipe, robertlipe+source@gpsbabel.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ */
+
+#include <QChar>
+#include <QDebug>
+#include <QIODevice>
+#include <QString>
+#include <QStringList>
+#include <QtGlobal>
+
+#include "src/core/textstream.h"
+
+#include "mynav.h"
+
+/***************************************************************************
+ * local helper functions *
+ ***************************************************************************/
+
+void
+MyNavFormat::read_line(const QString& line, route_head* track)
+{
+ const QStringList fields = line.split('|');
+
+ if (global_opts.debug_level > 1) {
+ qDebug() << "line: " << line;
+ for (int i = 0; i < fields.size(); i++) {
+ qDebug() << "field" << i << fields.at(i);
+ }
+ }
+
+ // don't consider lines without latitude/longitude
+ if (fields.size() <= fld_lat) {
+ return;
+ }
+
+ // only type 1 and type 5 lines contain coordinates
+ bool ok = false;
+ int line_type = fields.at(fld_type).trimmed().toInt(&ok);
+ if (!ok) {
+ return;
+ }
+ if (line_type != line_sensors && line_type != line_gps) {
+ return;
+ }
+
+ // This field is not present in .trc files, only in .ftn, so
+ // ignore line if present and != 1
+ if (fields.size() > fld_gps_valid) {
+ int val_gps_valid = fields.at(fld_gps_valid).trimmed().toInt(&ok);
+ if (!ok || val_gps_valid != 1) {
+ return;
+ }
+ }
+
+ double val_lon = fields.at(fld_lon).trimmed().toDouble(&ok) / 3600000.0;
+ if (!ok) {
+ return;
+ }
+ double val_lat = fields.at(fld_lat).trimmed().toDouble(&ok) / 3600000.0;
+ if (!ok) {
+ return;
+ }
+
+ auto* wpt = new Waypoint;
+ wpt->latitude = val_lat;
+ wpt->longitude = val_lon;
+
+ if (fields.size() > fld_altitude) {
+ double val_alt = fields.at(fld_altitude).trimmed().toDouble(&ok);
+ if (ok) {
+ wpt->altitude = val_alt;
+ }
+ }
+
+ if (fields.size() > fld_timestamp) {
+ int val_time = fields.at(fld_timestamp).trimmed().toInt(&ok);
+ if (ok) {
+ wpt->SetCreationTime(val_time);
+ }
+ }
+
+ track_add_wpt(track, wpt);
+}
+
+/***************************************************************************
+ * entry points called by gpsbabel main process *
+ ***************************************************************************/
+
+void
+MyNavFormat::rd_init(const QString& fname)
+{
+ read_fname = fname;
+}
+
+void
+MyNavFormat::rd_deinit()
+{
+ read_fname.clear();
+}
+
+void
+MyNavFormat::read()
+{
+ gpsbabel::TextStream stream;
+ stream.open(read_fname, QIODevice::ReadOnly, "mynav");
+
+ auto* track = new route_head;
+ track_add_head(track);
+
+ QString buf;
+ while (stream.readLineInto(&buf)) {
+ buf = buf.trimmed();
+ if ((buf.isEmpty()) || buf.startsWith('#')) {
+ continue;
+ }
+ read_line(buf, track);
+ }
+
+ stream.close();
+}
--- /dev/null
+/*
+ Handle MyNav TRC format .trc and .ftn files
+
+ Copyright (c) 2014-2020 Ralf Horstmann <ralf@ackstorm.de>
+ Copyright (C) 2014-2020 Robert Lipe, robertlipe+source@gpsbabel.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ */
+
+#ifndef MYNAV_H_INCLUDED_
+#define MYNAV_H_INCLUDED_
+
+#include <QString>
+#include <QVector>
+
+#include "defs.h"
+#include "format.h"
+
+class MyNavFormat : public Format
+{
+public:
+ ff_type get_type() const override
+ {
+ return ff_type_file;
+ }
+
+ QVector<ff_cap> get_cap() const override
+ {
+ return {
+ ff_cap_none, // waypoints
+ ff_cap_read, // tracks
+ ff_cap_none // routes
+ };
+ }
+
+ QString get_encode() const override
+ {
+ return CET_CHARSET_ASCII;
+ }
+
+ int get_fixed_encode() const override
+ {
+ return 0;
+ }
+
+ void rd_init(const QString& fname) override;
+ void read() override;
+ void rd_deinit() override;
+
+private:
+ enum field_e {
+ fld_type = 0,
+ fld_lon,
+ fld_lat,
+ fld_direction,
+ fld_speed,
+ fld_altitude,
+ fld_timestamp,
+ fld_duration,
+ fld_gps_valid,
+ fld_distance,
+ fld_ascent,
+ fld_cadence,
+ fld_heart_rate,
+ fld_id,
+ fld_total_duration,
+ fld_terminator
+ };
+
+ enum line_e {
+ line_header = 0,
+ line_sensors = 1,
+ line_geonote = 2,
+ line_gps = 5,
+ line_lap_pause = 7,
+ line_lap_restart = 8,
+ line_total = 9,
+ line_lap_start = 10,
+ line_lap_end = 11,
+ };
+
+ static void read_line(const QString& line, route_head* track);
+
+ QString read_fname;
+
+};
+
+#endif
<file>style/gpsdrivetrack.style</file>
<file>style/iblue747.style</file>
<file>style/iblue757.style</file>
- <file>style/igo2008_poi.style</file>
- <file>style/igoprimo_poi.style</file>
- <file>style/kompass_tk.style</file>
- <file>style/kompass_wp.style</file>
<file>style/land_air_sea.style</file>
- <file>style/mainnav.style</file>
- <file>style/mapconverter.style</file>
- <file>style/motoactv.style</file>
- <file>style/mxf.style</file>
<file>style/navigonwpt.style</file>
<file>style/nima.style</file>
<file>style/openoffice.style</file>
+++ /dev/null
-/*
-
- Support for IGN Rando track files.
-
- Copyright (C) 2005,2006 Olaf Klein, o.b.klein@gpsbabel.org
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-
-#include <cstdio> // for sscanf
-#include <cstdlib> // for atoi
-#include <ctime> // for strftime, localtime, time_t, tm
-
-#include <QByteArray> // for QByteArray
-#include <QIODevice> // for QIODevice, QIODeviceBase::ReadOnly
-#include <QList> // for QList
-#include <QString> // for QString, operator==
-#include <QXmlStreamAttributes> // for QXmlStreamAttributes
-#include <QtGlobal> // for QT_VERSION, QT_VERSION_CHECK, qPrintable
-
-#include "defs.h"
-#include "gbfile.h" // for gbfprintf, gbfclose, gbfopen, gbfile
-#include "src/core/datetime.h" // for DateTime
-#include "src/core/file.h" // for File
-#include "xmlgeneric.h" // for xg_callback, xg_string, cb_cdata, xml_deinit, xml_init, xml_readunicode, cb_start, cb_end, xg_cb_type, xg_tag_mapping
-
-
-#define MYNAME "IGNRando"
-
-#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
-static QString rd_fname;
-#endif
-static gbfile* fout;
-
-static route_head* track;
-static Waypoint* wpt;
-static int track_index; /* index of track we'll write */
-static int track_num; /* current index of track within track_disp_all */
-
-static int xmlpoints;
-
-/* options */
-static char* index_opt = nullptr;
-
-static QVector<arglist_t> ignr_args = {
- {"index", &index_opt, "Index of track to write (if more than one in source)", nullptr, ARGTYPE_INT, "1", nullptr , nullptr},
-};
-
-
-static xg_callback ignr_start;
-static xg_callback ignr_nb_etapes, ignr_descr;
-static xg_callback ignr_etape_begin, ignr_etape_end;
-static xg_callback ignr_etape_pos, ignr_etape_alt;
-
-static
-xg_tag_mapping ignr_xml_map[] = {
- { ignr_start, cb_start, "/RANDONNEE" },
- { ignr_nb_etapes, cb_cdata, "/RANDONNEE/INFORMATIONS/NB_ETAPES" },
- { ignr_descr, cb_cdata, "/RANDONNEE/INFORMATIONS/DESCRIPTION" },
- { ignr_etape_begin, cb_start, "/RANDONNEE/ETAPE" },
- { ignr_etape_end, cb_end, "/RANDONNEE/ETAPE" },
- { ignr_etape_pos, cb_cdata, "/RANDONNEE/ETAPE/POSITION" },
- { ignr_etape_alt, cb_cdata, "/RANDONNEE/ETAPE/ALTITUDE" },
- { nullptr, (xg_cb_type)0, nullptr }
-};
-
-static void
-ignr_xml_error(int condition)
-{
- if (condition != 0) {
- fatal(MYNAME ": Error in XML structure!\n");
- }
-}
-
-/* xmlgeneric callbacks */
-
-static void
-ignr_start(xg_string, const QXmlStreamAttributes*)
-{
- ignr_xml_error((track != nullptr));
-
- track = new route_head;
- track_add_head(track);
-}
-
-static void
-ignr_nb_etapes(xg_string args, const QXmlStreamAttributes*)
-{
- xmlpoints = args.toInt();
-}
-
-static void
-ignr_descr(xg_string args, const QXmlStreamAttributes*)
-{
- ignr_xml_error((track == nullptr));
- track->rte_desc = args;
-}
-
-static void
-ignr_etape_begin(xg_string, const QXmlStreamAttributes*)
-{
- ignr_xml_error((wpt != nullptr));
-
- wpt = new Waypoint;
-}
-
-static void
-ignr_etape_end(xg_string, const QXmlStreamAttributes*)
-{
- ignr_xml_error((track == nullptr) || (wpt == nullptr));
-
- track_add_wpt(track, wpt);
- wpt = nullptr;
-}
-
-static void
-ignr_etape_pos(xg_string args, const QXmlStreamAttributes*)
-{
- ignr_xml_error((wpt == nullptr) || (args.isEmpty()));
-
- if (2 != sscanf(STRFROMUNICODE(args), "%lf,%lf", &wpt->latitude, &wpt->longitude)) {
- fatal(MYNAME ": Invalid coordinates \"%s\"!\n", qPrintable(args));
- }
-}
-
-static void
-ignr_etape_alt(xg_string args, const QXmlStreamAttributes*)
-{
- ignr_xml_error((wpt == nullptr));
- if (args == nullptr) {
- return;
- }
-
- if (1 != sscanf(STRFROMUNICODE(args), "%lf", &wpt->altitude)) {
- fatal(MYNAME ": Invalid altitude \"%s\"!\n", qPrintable(args));
- }
-}
-
-/* callbacks registered in ignr_vecs */
-
-static void
-ignr_rd_init(const QString& fname)
-{
-#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
- xml_init(fname, ignr_xml_map, nullptr);
-#else
- rd_fname = fname;
- xml_init(nullptr, ignr_xml_map, nullptr);
-#endif
- wpt = nullptr;
- track = nullptr;
-}
-
-static void
-ignr_rd_deinit()
-{
- xml_deinit();
-#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
- rd_fname.clear();
-#endif
-}
-
-static void
-ignr_read()
-{
-#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
- // QXmlStreamReader had access to the windows-1252 QTextCodec that we expect
- // to find in the XMLDecl.
- xml_read();
-#else
- // QXmlStreamReader doesn't have access to a windows-1252 QStringDecoder,
- // and will throw an error if we pass a QIODevice when it sees windows-1252
- // in the XMLDecl.
- // Therfore we must decode the input manually and pass a QString.
- // With a QString QXmlStreamReader will ignore the XMLDecl.
- gpsbabel::File file(rd_fname);
- file.open(QIODevice::ReadOnly);
- xml_readunicode(STRTOUNICODE(file.readAll()));
- file.close();
-#endif
-}
-
-/* write support */
-
-/* callbacks registered in ignr_vecs */
-
-static void
-ignr_rw_init(const QString& fname)
-{
- fout = gbfopen(fname, "w", MYNAME);
-}
-
-static void
-ignr_rw_deinit()
-{
- gbfclose(fout);
-}
-
-static void
-ignr_write_track_hdr(const route_head* track_hdr)
-{
- track_num++;
-
- if (track_num != track_index) {
- return;
- }
-
- gbfprintf(fout, "\t<INFORMATIONS>\n");
- gbfprintf(fout, "\t\t<NB_ETAPES>%d</NB_ETAPES>\n", track_hdr->rte_waypt_ct());
- if (!track_hdr->rte_desc.isEmpty()) {
- gbfprintf(fout, "\t\t<DESCRIPTION>%s</DESCRIPTION>\n", STRFROMUNICODE(track_hdr->rte_desc));
- }
- gbfprintf(fout, "\t</INFORMATIONS>\n");
-}
-
-static void
-ignr_write_waypt(const Waypoint* waypoint)
-{
- if (track_num != track_index) {
- return;
- }
-
- gbfprintf(fout, "\t<ETAPE>\n");
- gbfprintf(fout, "\t\t<POSITION>%3.6f,%3.6f</POSITION>\n", waypoint->latitude, waypoint->longitude);
- if (waypoint->altitude != unknown_alt) {
- gbfprintf(fout, "\t\t<ALTITUDE>%3.6f</ALTITUDE>\n", waypoint->altitude);
- }
- gbfprintf(fout, "\t</ETAPE>\n");
-}
-
-static void
-ignr_write()
-{
- time_t now;
- struct tm tm;
- char buff[32];
-
- if (index_opt != nullptr) {
- track_index = atoi(index_opt);
- if ((track_index < 1) || (track_index > (int) track_count()))
- fatal(MYNAME ": Invalid track index %d (we have currently %d track(s))!\n",
- track_index, track_count());
- } else {
- track_index = 1;
- }
- track_num = 0;
-
- now = current_time().toTime_t();
- tm = *localtime(&now);
-
- gbfprintf(fout, "<?xml version=\"1.0\" encoding=\"windows-1252\"?>\n");
- gbfprintf(fout, "<RANDONNEE>\n");
- gbfprintf(fout, "\t<ENTETE>\n");
- gbfprintf(fout, "\t\t<VERSION_XML>1.1</VERSION_XML>\n");
- gbfprintf(fout, "\t\t<VERSION_BASE>IHA03AA</VERSION_BASE>\n");
-
- strftime(buff, sizeof(buff), "%d/%m/%Y", &tm);
- gbfprintf(fout, "\t\t<DATE>%s</DATE>\n", buff);
- strftime(buff, sizeof(buff), "%H:%M:%S", &tm);
- gbfprintf(fout, "\t\t<HEURE>%s</HEURE>\n", buff);
-
- gbfprintf(fout, "\t</ENTETE>\n");
- track_disp_all(ignr_write_track_hdr, nullptr, ignr_write_waypt);
- gbfprintf(fout, "</RANDONNEE>\n");
-}
-
-ff_vecs_t ignr_vecs = {
- ff_type_file,
- { ff_cap_none, (ff_cap)(ff_cap_read | ff_cap_write), ff_cap_none },
- ignr_rd_init,
- ignr_rw_init,
- ignr_rd_deinit,
- ignr_rw_deinit,
- ignr_read,
- ignr_write,
- nullptr,
- &ignr_args,
- CET_CHARSET_MS_ANSI, 1
- , NULL_POS_OPS
-};
+++ /dev/null
-/*
- IGO8 Track Format
-
- Copyright (C) 2008 Dustin Johnson, Dustin@Dustinj.us
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
- July 26, 2008 - Dustin: Added tracknum, title, and description options
- July 26, 2008 - Dustin: Validated the new code for char to Unicode conversion
- */
-
-
-/*
- iGo8 (*.trk) Format Overview
-
- |------------------------------| <--\
- | ID Block (20B) | |
- |------------------------------| |
- | | |
- | |
- | | H
- | | e
- | | a
- | Description Block (256B) | d
- | | e
- | | r
- | |
- | | |
- | | |
- | | |
- |------------------------------| <--/
- | Information Block (12B) |
- |------------------------------|
- | Waypoint 1 |
- |------------------------------|
- | Waypoint 2 |
- |------------------------------|
- | Waypoint 3 |
- |------------------------------|
- | ... |
- |------------------------------|
-
- ID Block: defined by igo8_id_block
- Description Block: Two null-terminated unicode 2 strings.
- The first is the title of the track,
- the second is the description.
- Information Block: defined by igo8_information_block
- Waypoint: defined by igo8_point
-
-*/
-
-#include <cstdio> // for SEEK_SET
-#include <cstdint>
-#include <cstdlib> // for atoi
-#include <cstring> // for memset
-
-#include <QChar> // for QChar
-#include <QString> // for QString
-#include <QVector> // for QVector
-
-#include "defs.h"
-#include "gbfile.h" // for gbfwrite, gbfclose, gbfseek, gbfgetint32, gbfread, gbfile, gbfopen_le
-#include "src/core/datetime.h" // for DateTime
-
-
-#define FLOAT_TO_INT(x) ((int)((x) + ((x)<0?-0.5:0.5)))
-#define IGO8_HEADER_SIZE (sizeof(igo8_id_block) + 256)
-#define MYNAME "IGO8"
-
-struct igo8_id_block {
- uint32_t unknown_1;
- uint32_t unknown_2;
- uint32_t unknown_3;
- uint32_t track_number;
- uint32_t unknown_4;
-};
-using p_igo8_id_block = igo8_id_block*;
-
-struct igo8_information_block {
- uint32_t start_time; // In Unix time
- uint32_t zero; // Doesn't appear to serve a purpose
- uint32_t total_file_size; // In bytes
-};
-using p_igo8_information_block = igo8_information_block*;
-
-struct igo8_point {
- uint32_t unix_time;
- uint32_t lon;
- uint32_t lat;
-};
-using p_igo8_point = igo8_point*;
-
-// Files
-static gbfile* igo8_file_in;
-static gbfile* igo8_file_out;
-
-// Options
-static char* igo8_option_tracknum = nullptr;
-static char* igo8_option_title = nullptr;
-static char* igo8_option_description = nullptr;
-
-// Internal state
-static uint32_t invented_time;
-static uint32_t point_count;
-static int in_point_count;
-
-// Exported options list
-static QVector<arglist_t> igo8_options = {
- { "tracknum", &igo8_option_tracknum, "Track identification number", nullptr, ARGTYPE_INT, ARG_NOMINMAX, nullptr },
- { "title", &igo8_option_title, "Track title", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr },
- { "description", &igo8_option_description, "Track description", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr },
-};
-
-// Sanity check
-static void igo8_check_type_sizes()
-{
- if constexpr(sizeof(igo8_point) != 12) {
- fatal(MYNAME ": igo8_point is %ld bytes instead of the required 12.\n",
- (long) sizeof(igo8_point));
- }
-
- if constexpr(sizeof(igo8_information_block) != 12) {
- fatal(MYNAME ": igo8_information_block is %ld bytes instead of the required 12.\n",
- (long) sizeof(igo8_information_block));
- }
-
- if constexpr(sizeof(igo8_id_block) != 20) {
- fatal(MYNAME ": igo8_id_block is %ld bytes instead of the required 20.\n",
- (long) sizeof(igo8_id_block));
- }
-}
-
-// Reader initialization callback
-static void igo8_read_init(const QString& fname)
-{
- igo8_file_in = gbfopen_le(fname, "rb", MYNAME);
-
- // Make sure that we are in the environment we expect and require
- igo8_check_type_sizes();
-
- // Seek past the header and most of the Information Block. Read
- // the last word for trackpoint count since latest igo8 seems to
- // zero-pad the files.
- gbfseek(igo8_file_in, IGO8_HEADER_SIZE + sizeof(igo8_information_block) - 4, SEEK_SET);
- in_point_count = (gbfgetint32(igo8_file_in) - IGO8_HEADER_SIZE -
- sizeof(igo8_information_block)) / sizeof(igo8_point);
-}
-
-// Reader callback
-static void igo8_read()
-{
- igo8_point point;
-
- auto* track_head = new route_head;
- track_add_head(track_head);
-
- while (in_point_count &&
- gbfread(&point, sizeof(point), 1, igo8_file_in) > 0) {
- in_point_count--;
- auto* wpt_tmp = new Waypoint;
-
- wpt_tmp->latitude = le_read32(&point.lat) / (double)0x800000;
- wpt_tmp->longitude = le_read32(&point.lon) / (double)0x800000;
- wpt_tmp->SetCreationTime(le_read32(&point.unix_time));
-
- track_add_wpt(track_head, wpt_tmp);
- }
-}
-
-// Reader close callback
-static void igo8_read_deinit()
-{
- gbfclose(igo8_file_in);
-}
-
-// Writer initialize callback
-static void igo8_write_init(const QString& fname)
-{
- igo8_file_out = gbfopen_le(fname, "wb", MYNAME);
-
- igo8_check_type_sizes();
-
- invented_time = 1;
- point_count = 0;
-}
-
-// Writer close callback
-static void igo8_write_deinit()
-{
- uint32_t normalized_file_size;
-
- // Seek to the start of the third long in the Information Block, this is
- // where we will write out the total size of the file.
- gbfseek(igo8_file_out, IGO8_HEADER_SIZE + sizeof(uint32_t)*2, SEEK_SET);
-
- // The total size of the file is the number of points written + Information block + Header
- le_write32(&normalized_file_size, sizeof(igo8_point)*(point_count) + sizeof(igo8_information_block) + IGO8_HEADER_SIZE);
-
- // Write the size
- gbfwrite(&normalized_file_size, sizeof(normalized_file_size), 1, igo8_file_out);
-
- gbfclose(igo8_file_out);
-}
-
-// Write point callback
-static void write_igo8_track_point(const Waypoint* wpt)
-{
- igo8_point point;
-
- memset(&point, 0, sizeof(point));
-
- // iGo8 appears to expect a time, if one isn't provided
- // then we shall make our own, where each point is one
- // second apart.
- if (wpt->creation_time.isValid()) {
- le_write32(&point.unix_time, wpt->GetCreationTime().toTime_t());
- } else {
- le_write32(&point.unix_time, invented_time++);
- }
-
- // Write the first part of the Information Block, the start time
- if (point_count == 0) {
- gbfwrite(&point, sizeof(point), 1, igo8_file_out);
- }
-
- le_write32(&point.lon, FLOAT_TO_INT(wpt->longitude * 0x800000));
- le_write32(&point.lat, FLOAT_TO_INT(wpt->latitude * 0x800000));
-
- gbfwrite(&point, sizeof(point), 1, igo8_file_out);
-
- // Count the number of point printed, we will use this at the end to
- // finish filling out the Information Block.
- point_count++;
-}
-
-// Write src unicode str to the dst cstring using unicode characters.
-// dst_max_length is in bytes.
-// I have no idea if iGo8 even supports real unicode 2, but is does look like
-// it as every ascii character is a short with the ascii character as the
-// least significant 7 bits.
-static unsigned int print_unicode(char* dst, int dst_max_length, const QString& src)
-{
- int max_qchars = dst_max_length / 2;
- if (max_qchars < 1) {
- // We must have room for the terminator.
- fatal(MYNAME ": igo8 header overflow.\n");
- }
- // Write as many characters from the source as possible
- // while leaving space for a terminator.
- int n_src_qchars = src.size() > (max_qchars - 1) ? max_qchars - 1 : src.size();
- for (int i = 0; i < n_src_qchars; ++i) {
- le_write16(dst, src.at(i).unicode());
- dst += 2;
- }
- le_write16(dst, 0); // NULL (U+0000) terminator
-
- return (n_src_qchars + 1) * 2;
-}
-
-static void write_header()
-{
- char header[IGO8_HEADER_SIZE] = {};
- igo8_id_block tmp_id_block;
- auto* id_block = (p_igo8_id_block)header;
- uint32_t current_position = 0;
- const char* title = "Title";
- const char* description = "Description";
-
- // These values seem to be constant for me, but I have no idea what they are.
- tmp_id_block.unknown_1 = 0x0000029B;
- tmp_id_block.unknown_2 = 0x000003E7;
- tmp_id_block.unknown_3 = 0x00000003;
-
- // This appears to be a unique number that IDs the track.
- // It is mono-incrementing and offset by 2 above the track number.
- // e.g. "Track 1" --> track_number = 3
- // XXX - Dustin: My guess is that this number is used as the key for the track color, if
- // XXX - Dustin: multiple tracks have the same color they will be colored the same, just
- // XXX - Dustin: a guess though.
- if (igo8_option_tracknum) {
- tmp_id_block.track_number = atoi(igo8_option_tracknum);
- } else {
- tmp_id_block.track_number = 0x00000010;
- }
- tmp_id_block.unknown_4 = 0x00000001;
-
- // Byte swap out to the header buffer.
- le_write32(&id_block->unknown_1, tmp_id_block.unknown_1);
- le_write32(&id_block->unknown_2, tmp_id_block.unknown_2);
- le_write32(&id_block->unknown_3, tmp_id_block.unknown_3);
- le_write32(&id_block->track_number, tmp_id_block.track_number);
- le_write32(&id_block->unknown_4, tmp_id_block.unknown_4);
-
- // Move past the ID block, we have just filled it.
- current_position += sizeof(*id_block);
-
- // Set the title of the track
- // Note: we shorten the length of the potential title by 2 because we need to leave at
- // least enough room to have a null for the description string that follows it.
- if (igo8_option_title) {
- title = igo8_option_title;
- }
- current_position += print_unicode((header+current_position), IGO8_HEADER_SIZE - current_position - 2, title);
-
- // Set the description of the track
- if (igo8_option_description) {
- description = igo8_option_description;
- }
- current_position += print_unicode((header+current_position), IGO8_HEADER_SIZE - current_position, description);
-
- gbfwrite(&header, IGO8_HEADER_SIZE, 1, igo8_file_out);
-}
-
-// Writer callback
-static void igo8_write()
-{
- write_header();
- track_disp_all(nullptr, nullptr, write_igo8_track_point);
-}
-
-// Callback definitions
-ff_vecs_t igo8_vecs = {
- ff_type_file,
- { ff_cap_none, (ff_cap)(ff_cap_read | ff_cap_write), ff_cap_none },
- igo8_read_init,
- igo8_write_init,
- igo8_read_deinit,
- igo8_write_deinit,
- igo8_read,
- igo8_write,
- nullptr,
- &igo8_options,
- CET_CHARSET_UTF8,
- 1
- , NULL_POS_OPS
-};
+++ /dev/null
-/*
-
- Support for "MagicMaps" project files (.ikt)
-
- Copyright (C) 2008 Olaf Klein, o.b.klein@gpsbabel.org
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-*/
-
-
-#include "defs.h"
-#include "xmlgeneric.h"
-#include <QXmlStreamAttributes>
-
-static QVector<arglist_t> ikt_args = {
-};
-
-#define MYNAME "ikt"
-
-static QString name, text;
-
-static route_head* track;
-static Waypoint* waypt;
-
-static xg_callback iktobj_waypt, iktobj_type, iktobj_name, iktobj_trkpt, iktobj_text;
-
-#define IKTOBJ "/Root/Content/MMGeoObjects/MMGeoObject"
-
-/* Here we are working with wildcards in the tag list.
- Please ensure that the longest entries comes first */
-
-static
-xg_tag_mapping ikt_map[] = {
- { iktobj_trkpt, cb_start, IKTOBJ "_*/PathPoints/Point_*/GeoPosition" },
- { iktobj_type, cb_cdata, IKTOBJ "_*/GeoObjectType" },
- { iktobj_waypt, cb_start, IKTOBJ "_*/GeoPosition" },
- { iktobj_name, cb_cdata, IKTOBJ "_*/Name" },
- { iktobj_text, cb_cdata, IKTOBJ "_*/POIDrawable2D/Text" },
- { nullptr, (xg_cb_type)0, nullptr }
-};
-
-static void
-ikt_object_end()
-{
- if (track) {
- track->rte_name = name;
- track_add_head(track);
- } else if (waypt) {
- waypt->shortname = name;
- waypt->description = text;
- waypt_add(waypt);
- }
-
- name = QString();
- text = QString();
- track = nullptr;
- waypt = nullptr;
-}
-
-static void
-iktobj_waypt(xg_string, const QXmlStreamAttributes* attrv)
-{
- if (attrv->hasAttribute("X")) {
- waypt->longitude = attrv->value("X").toDouble();
- }
- if (attrv->hasAttribute("Y")) {
- waypt->latitude = attrv->value("Y").toDouble();
- }
-}
-
-static void
-iktobj_trkpt(xg_string args, const QXmlStreamAttributes* attrv)
-{
- waypt = new Waypoint;
- iktobj_waypt(args, attrv);
- track_add_wpt(track, waypt);
- waypt = nullptr;
-}
-
-static void
-iktobj_name(xg_string args, const QXmlStreamAttributes*)
-{
- name = args;
-}
-
-static void
-iktobj_text(xg_string args, const QXmlStreamAttributes*)
-{
- text = args;
-}
-
-static void
-iktobj_type(xg_string args, const QXmlStreamAttributes*)
-{
- ikt_object_end();
- switch (args.toInt()) {
- case 0:
- waypt = new Waypoint;
- break;
- case 1:
- track = new route_head;
- break;
- default:
- fatal(MYNAME ": Unknown object type %s!\n", qPrintable(args));
- }
-}
-
-static void
-ikt_rd_init(const QString& fname)
-{
- xml_init(fname, ikt_map, nullptr);
-
- track = nullptr;
- waypt = nullptr;
- name = QString();
- text = QString();
-}
-
-static void
-ikt_read()
-{
- xml_read();
-}
-
-static void
-ikt_rd_deinit()
-{
- ikt_object_end();
- xml_deinit();
-}
-
-ff_vecs_t ik3d_vecs = {
- ff_type_file,
- {
- ff_cap_read, /* waypoints */
- ff_cap_read, /* tracks */
- ff_cap_none /* routes */
- },
- ikt_rd_init,
- nullptr,
- ikt_rd_deinit,
- nullptr,
- ikt_read,
- nullptr,
- nullptr,
- &ikt_args,
- CET_CHARSET_UTF8, 1
- , NULL_POS_OPS
-};
+++ /dev/null
-/*
- Access Nokia Landmark Exchange files.
-
- Copyright (C) 2007 Robert Lipe, robertlipe+source@gpsbabel.org
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
- */
-
-
-/*
- * Nokia's Landmark Exchange (LMX) format is a straight-forward XML
- * format. Though they do support a compact binary representation,
- * we don't implement that at this time in GPSBabel.
- */
-
-#include <QString> // for QString
-#include <QXmlStreamAttributes> // for QXmlStreamAttributes
-
-#include "defs.h"
-#include "gbfile.h" // for gbfputc, gbfprintf, gbfclose, gbfopen, gbfputcstr, gbfputs, gbfile, gbfputuint16
-#include "xmlgeneric.h" // for cb_cdata, xg_callback, xg_string, cb_end, cb_start, xg_cb_type, xml_deinit, xml_init, xml_read, xg_tag_mapping
-
-
-static gbfile* ofd;
-static Waypoint* wpt_tmp;
-static QString urllink;
-static QString urllinkt;
-static char* binary = nullptr;
-
-#define MYNAME "lmx"
-
-static
-QVector<arglist_t> lmx_args = {
- {
- "binary", &binary,
- "Compact binary representation",
- nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
- },
-};
-
-/*
- * Writer
- */
-
-
-static void
-lmx_wr_init(const QString& fname)
-{
- ofd = gbfopen(fname, "w", MYNAME);
-}
-
-static void
-lmx_wr_deinit()
-{
- gbfclose(ofd);
-}
-
-static const char*
-lmx_stag(int tag)
-{
- switch (tag) {
- case 0xC5:
- return "lmx";
- case 0x46:
- return "landmarkCollection";
- case 0x47:
- return "landmark";
- case 0x48:
- return "name";
- case 0x49:
- return "description";
- case 0x4A:
- return "coordinates";
- case 0x4B:
- return "latitude";
- case 0x4C:
- return "longitude";
- case 0x4D:
- return "altitude";
- case 0x4E:
- return "horizontalAccuracy";
- case 0x4F:
- return "verticalAccuracy";
- case 0x50:
- return "timeStamp";
- case 0x51:
- return "coverageRadius";
- case 0x52:
- return "category";
- case 0x53:
- return "id";
- case 0x54:
- return "addressInfo";
- case 0x55:
- return "country";
- case 0x56:
- return "countryCode";
- case 0x57:
- return "state";
- case 0x58:
- return "county";
- case 0x59:
- return "city";
- case 0x5A:
- return "district";
- case 0x5B:
- return "postalCode";
- case 0x5C:
- return "crossing1";
- case 0x5D:
- return "crossing2";
- case 0x5E:
- return "street";
- case 0x5F:
- return "buildingName";
- case 0x60:
- return "buildingFloor";
- case 0x61:
- return "buildingZone";
- case 0x62:
- return "buildingRoom";
- case 0x63:
- return "extension";
- case 0x64:
- return "phoneNumber";
- case 0x65:
- return "mediaLink";
- case 0x66:
- return "mime";
- case 0x67:
- return "url";
- default:
- return nullptr;
- }
-}
-
-static void
-lmx_indent(int count)
-{
- for (int i = 0; i<count; i++) {
- gbfputc('\t', ofd);
- }
-}
-
-static void
-lmx_start_tag(int tag, int indent)
-{
- if (binary) {
- gbfputc(tag, ofd);
- } else {
- lmx_indent(indent);
- gbfprintf(ofd, "<lm:%s>", lmx_stag(tag));
- }
-}
-
-static void
-lmx_end_tag(int tag, int indent)
-{
- if (binary) {
- gbfputc(0x01, ofd);
- } else {
- lmx_indent(indent);
- gbfprintf(ofd, "</lm:%s>\n", lmx_stag(tag));
- }
-}
-
-static void
-lmx_write_xml(int tag, const QString& data, int indent)
-{
- lmx_start_tag(tag, indent);
-
- if (binary) {
- gbfputc(0x03, ofd); // inline string follows
- gbfputcstr(CSTR(data), ofd);
- } else {
- char* tmp_ent = xml_entitize(CSTR(data));
- gbfputs(tmp_ent, ofd);
- xfree(tmp_ent);
- }
-
- lmx_end_tag(tag, 0);
-}
-
-static void
-lmx_print(const Waypoint* wpt)
-{
- /*
- * Desperation time, try very hard to get a good shortname
- */
- QString odesc = wpt->notes;
- if (odesc.isEmpty()) {
- odesc = wpt->description;
- }
- if (odesc.isEmpty()) {
- odesc = wpt->shortname;
- }
-
- QString oname = global_opts.synthesize_shortnames ? odesc : wpt->shortname;
-
- lmx_start_tag(0x47, 2); // landmark
- if (!binary) {
- gbfputc('\n', ofd);
- }
- if (!oname.isEmpty()) {
- lmx_write_xml(0x48, oname, 3); // name
- }
- if (!wpt->description.isEmpty()) {
- lmx_write_xml(0x49, wpt->description, 3); // description
- }
- lmx_start_tag(0x4A, 3); // coordinates
- if (!binary) {
- gbfputc('\n', ofd);
- }
-
- lmx_write_xml(0x4B, QString::number(wpt->latitude, 'f'), 4); // latitude
-
- lmx_write_xml(0x4C, QString::number(wpt->longitude, 'f'), 4); // longitude
-
- if (wpt->altitude && (wpt->altitude != unknown_alt)) {
- lmx_write_xml(0x4D, QString::number(wpt->altitude, 'f'), 4); // altitude
- }
- lmx_end_tag(0x4A, 3); // coordinates
-
- if (wpt->HasUrlLink()) {
- lmx_start_tag(0x65, 3); // mediaLink
- if (!binary) {
- gbfputc('\n', ofd);
- }
- UrlLink link = wpt->GetUrlLink();
- if (!link.url_link_text_.isEmpty()) {
- lmx_write_xml(0x48, link.url_link_text_, 4); // name
- }
- lmx_write_xml(0x67, link.url_, 4); // url
- lmx_end_tag(0x65, 3); // mediaLink
- }
-
- lmx_end_tag(0x47, 2); // landmark
-}
-
-
-static void
-lmx_write()
-{
- if (binary) {
- gbfputc(0x03, ofd); // WBXML version 1.3
- gbfputuint16(0x04A4, ofd); // "-//NOKIA//DTD LANDMARKS 1.0//EN"
- gbfputc(106, ofd); // Charset=UTF-8
- gbfputc(0x00, ofd); // empty string table
- gbfputc(0xC5, ofd); // lmx
- gbfputc(0x05, ofd); // xmlns=http://www.nokia.com/schemas/location/landmarks/
- gbfputc(0x85, ofd); // 1/0/
- gbfputc(0x06, ofd); // xmlns:xsi=
- gbfputc(0x86, ofd); // http://www.w3.org/2001/XMLSchema-instance
- gbfputc(0x07, ofd); // xsi:schemaLocation=http://www.nokia.com/schemas/location/landmarks/
- gbfputc(0x85, ofd); // 1/0/
- gbfputc(0x87, ofd); // whitespace
- gbfputc(0x88, ofd); // lmx.xsd
- gbfputc(0x01, ofd); // END lmx attributes
- } else {
- gbfprintf(ofd, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
- gbfprintf(ofd, "<lm:lmx xmlns:lm=\"http://www.nokia.com/schemas/location/landmarks/1/0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.nokia.com/schemas/location/landmarks/1/0/ lmx.xsd\">\n");
- }
-
- lmx_start_tag(0x46, 1); // landmarkCollection
- if (!binary) {
- gbfputc('\n', ofd);
- }
- waypt_disp_all(lmx_print);
- lmx_end_tag(0x46, 1); // landmarkCollection
- lmx_end_tag(0xC5, 0); // lmx
-}
-
-/*
- * Reader
- */
-
-static xg_callback lmx_lm_start, lmx_lm_end;
-static xg_callback lmx_lm_name,lmx_lm_desc;
-static xg_callback lmx_lm_lat, lmx_lm_lon, lmx_lm_alt;
-static xg_callback lmx_lm_mlink_s, lmx_lm_mlink_e;
-static xg_callback lmx_lm_link, lmx_lm_linkt;
-
-static xg_tag_mapping gl_map[] = {
-#define LM "/lm:lmx/lm:landmarkCollection/lm:landmark"
- { lmx_lm_start, cb_start, LM },
- { lmx_lm_end, cb_end, LM },
- { lmx_lm_name, cb_cdata, LM "/lm:name" },
- { lmx_lm_desc, cb_cdata, LM "/lm:description" },
- { lmx_lm_lat, cb_cdata, LM "/lm:coordinates/lm:latitude" },
- { lmx_lm_lon, cb_cdata, LM "/lm:coordinates/lm:longitude" },
- { lmx_lm_alt, cb_cdata, LM "/lm:coordinates/lm:altitude" },
- { lmx_lm_mlink_s, cb_start, LM "/lm:mediaLink" },
- { lmx_lm_link, cb_cdata, LM "/lm:mediaLink/lm:url" },
- { lmx_lm_linkt, cb_cdata, LM "/lm:mediaLink/lm:name" },
- { lmx_lm_mlink_e, cb_end, LM "/lm:mediaLink" },
- { nullptr, (xg_cb_type)0, nullptr}
-};
-
-static void
-lmx_rd_init(const QString& fname)
-{
- xml_init(fname, gl_map, nullptr);
-}
-
-static void
-lmx_read()
-{
- xml_read();
-}
-
-static void
-lmx_rd_deinit()
-{
- xml_deinit();
-}
-
-
-
-static void
-lmx_lm_start(xg_string, const QXmlStreamAttributes*)
-{
- wpt_tmp = new Waypoint;
-}
-
-static void
-lmx_lm_end(xg_string, const QXmlStreamAttributes*)
-{
- waypt_add(wpt_tmp);
-}
-
-static void
-lmx_lm_lat(xg_string args, const QXmlStreamAttributes*)
-{
- wpt_tmp->latitude = args.toDouble();
-}
-
-static void
-lmx_lm_lon(xg_string args, const QXmlStreamAttributes*)
-{
- wpt_tmp->longitude = args.toDouble();
-}
-
-static void
-lmx_lm_alt(xg_string args, const QXmlStreamAttributes*)
-{
- wpt_tmp->altitude = args.toDouble();
-}
-
-static void
-lmx_lm_name(xg_string args, const QXmlStreamAttributes*)
-{
- wpt_tmp->shortname = args;
-}
-
-static void
-lmx_lm_desc(xg_string args, const QXmlStreamAttributes*)
-{
- wpt_tmp->description = args;
-}
-
-static void
-lmx_lm_mlink_s(xg_string, const QXmlStreamAttributes*)
-{
- urllink = urllinkt = QString();
-}
-
-static void
-lmx_lm_link(xg_string args, const QXmlStreamAttributes*)
-{
- urllink = args;
-}
-
-static void
-lmx_lm_linkt(xg_string args, const QXmlStreamAttributes*)
-{
- urllinkt = args;
-}
-
-static void
-lmx_lm_mlink_e(xg_string, const QXmlStreamAttributes*)
-{
- waypt_add_url(wpt_tmp, urllink, urllinkt);
-}
-
-
-ff_vecs_t lmx_vecs = {
- ff_type_file,
- {
- (ff_cap)(ff_cap_read | ff_cap_write), /* waypoints */
- ff_cap_none, /* tracks */
- ff_cap_none /* routes */
- },
- lmx_rd_init,
- lmx_wr_init,
- lmx_rd_deinit,
- lmx_wr_deinit,
- lmx_read,
- lmx_write,
- nullptr,
- &lmx_args,
- CET_CHARSET_UTF8, 0 /* CET-REVIEW */
- , NULL_POS_OPS
-};
+++ /dev/null
-/*
-
- Support for MapAsia (.tr7) track file format.
-
- Copyright (C) 2008 Olaf Klein, o.b.klein@gpsbabel.org
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
- */
-
-#include <cmath> // for fabs
-#include <cstring> // for memset
-
-#include <QDate> // for QDate
-#include <QDateTime> // for QDateTime
-#include <QString> // for QString
-#include <QTime> // for QTime
-#include <Qt> // for UTC
-#include <QtGlobal> // for foreach
-
-#include "defs.h"
-#include "gbfile.h" // for gbfclose, gbfeof, gbfgetint32, gbfputint32, gbfread, gbfwrite, gbfile, gbfopen_le
-#include "session.h" // for curr_session
-#include "src/core/datetime.h" // for DateTime
-
-
-#define MYNAME "mapasia"
-
-#define TR7_TRACK_MAGIC 0x223EADB
-
-#define TR7_S_SIZE 32
-
-#define TR7_S_YEAR 0
-#define TR7_S_MONTH 2
-#define TR7_S_DAY 6
-#define TR7_S_HOUR 8
-#define TR7_S_MIN 10
-#define TR7_S_SEC 12
-#define TR7_S_LON 16
-#define TR7_S_LAT 20
-#define TR7_S_SPEED 24
-#define TR7_S_COURSE 26
-#define TR7_S_VALID 28
-#define TR7_S_FIX 29
-
-static gbfile* fin, *fout;
-static const Waypoint* wpt_tmp;
-static const route_head* trk_tmp;
-static int course_tmp, speed_tmp;
-
-static
-QVector<arglist_t> tr7_args = {
-};
-
-/*******************************************************************************
-* %%% R E A D E R %%% *
-*******************************************************************************/
-
-static void
-tr7_rd_init(const QString& fname)
-{
- fin = gbfopen_le(fname, "rb", MYNAME);
-}
-
-static void
-tr7_read()
-{
- route_head* trk = nullptr;
- Waypoint* prev = nullptr;
-
- unsigned int magic = gbfgetint32(fin);
- if (magic != TR7_TRACK_MAGIC) {
- fatal(MYNAME ": Invalid magic number in header (%X, but %X expected)!\n", magic, TR7_TRACK_MAGIC);
- }
-
- while (! gbfeof(fin)) {
- unsigned char buff[TR7_S_SIZE];
-
- gbfread(buff, 1, sizeof(buff), fin);
-
- double lat = (double)le_read32(&buff[TR7_S_LAT]) / 1000000.0;
- double lon = (double)le_read32(&buff[TR7_S_LON]) / 1000000.0;
-
- if ((fabs(lat) > 90) || (fabs(lon) > 180)) { /* that really happens */
- trk = nullptr;
- continue;
- }
-
- QDate date(le_read16(&buff[TR7_S_YEAR]),
- buff[TR7_S_MONTH],
- buff[TR7_S_DAY]);
- QTime time(buff[TR7_S_HOUR],
- buff[TR7_S_MIN],
- buff[TR7_S_SEC]);
- if (!date.isValid() || !time.isValid()) {
- continue;
- }
-
- float speed = KPH_TO_MPS(le_read16(&buff[TR7_S_SPEED]));
- float course = 360 - le_read16(&buff[TR7_S_COURSE]);
- if ((speed < 0) || (course > 360) || (course < 0)) {
- continue;
- }
-
- auto* wpt = new Waypoint;
-
- wpt->latitude = lat;
- wpt->longitude = lon;
-
- wpt->SetCreationTime(QDateTime(date, time, Qt::UTC));
-
- WAYPT_SET(wpt, course, course);
- WAYPT_SET(wpt, speed, speed);
-
-#if 0 /* unsure, not validated items */
- wpt->fix = buff[TR7_S_FIX];
- if (buff[TR7_S_VALID] != 'A') {
- delete wpt;
- continue;
- }
-#endif
- if (waypt_speed(prev, wpt) > 9999.9) { /* filter out some bad trackpoints */
- delete wpt;
- continue;
- }
-
- if (prev) { /* other track or bad timestamp */
- if (wpt->creation_time.isValid() && (prev->creation_time.toTime_t() > wpt->creation_time.toTime_t())) {
- trk = nullptr;
- } else if (waypt_distance(prev, wpt) > 9999.9) {
- trk = nullptr;
- }
- }
-
- if (! trk) {
- trk = new route_head;
- track_add_head(trk);
- }
- track_add_wpt(trk, wpt);
- prev = wpt;
- }
-}
-
-static void
-tr7_check_after_read_head_cb(const route_head* trk)
-{
- trk_tmp = trk;
- course_tmp = 0;
- speed_tmp = 0;
-}
-
-static void
-tr7_check_after_read_wpt_cb(const Waypoint* wpt)
-{
- if (wpt->speed != 0) {
- speed_tmp = 1;
- }
- if (wpt->course != 360.0) {
- course_tmp = 1;
- }
-}
-
-static void
-tr7_check_after_read_trailer_cb(const route_head* trk)
-{
- foreach (Waypoint* wpt, trk->waypoint_list) {
- if (speed_tmp == 0) {
- WAYPT_UNSET(wpt, speed);
- }
- if (course_tmp == 0) {
- WAYPT_UNSET(wpt, course);
- wpt->course = 0;
- }
- }
-}
-
-static void
-tr7_rd_deinit()
-{
- track_disp_session(curr_session(),
- tr7_check_after_read_head_cb,
- tr7_check_after_read_trailer_cb,
- tr7_check_after_read_wpt_cb);
- gbfclose(fin);
-}
-
-/*******************************************************************************
-* %%% W R I T E R %%% *
-*******************************************************************************/
-
-static void
-tr7_disp_track_head_cb(const route_head*)
-{
- wpt_tmp = nullptr;
-}
-
-static void
-tr7_disp_waypt_cb(const Waypoint* wpt)
-{
- unsigned char buff[TR7_S_SIZE];
-
- memset(buff, 0, sizeof(buff));
-
- le_write32(&buff[TR7_S_LON], (int)(wpt->longitude * 1000000.0));
- le_write32(&buff[TR7_S_LAT], (int)(wpt->latitude * 1000000.0));
-
- double course;
- if WAYPT_HAS(wpt, course) {
- course = wpt->course;
- } else if (wpt_tmp != nullptr) {
- course = waypt_course(wpt_tmp, wpt);
- } else {
- course = -1;
- }
- if (course >= 0) {
- le_write16(&buff[TR7_S_COURSE], (int)(360 - course));
- }
-
- QDateTime dt = wpt->GetCreationTime().toUTC();
- if (dt.isValid()) {
- QDate d = dt.date();
-
- le_write16(&buff[TR7_S_YEAR], d.year());
- buff[TR7_S_MONTH] = d.month();
- buff[TR7_S_DAY] = d.day();
-
- QTime t = dt.time();
- buff[TR7_S_HOUR] = t.hour();
- buff[TR7_S_MIN] = t.minute();
- buff[TR7_S_SEC] = t.second();
-
- double speed;
- if WAYPT_HAS(wpt, speed) {
- speed = wpt->speed;
- } else if (wpt_tmp != nullptr) {
- speed = waypt_speed(wpt_tmp, wpt);
- } else {
- speed = -1;
- }
- if (speed >= 0) {
- le_write16(&buff[TR7_S_SPEED], (int)MPS_TO_KPH(speed));
- }
- }
- buff[TR7_S_VALID] = 'A'; /* meaning unknown */
-
-#if 0 /* not validated */
- if (wpt->fix != fix_unknown) {
- buff[TR7_S_FIX] = wpt->fix;
- }
-#endif
- gbfwrite(buff, 1, sizeof(buff), fout);
-
- wpt_tmp = wpt;
-}
-
-static void
-tr7_wr_init(const QString& fname)
-{
- fout = gbfopen_le(fname, "wb", MYNAME);
- gbfputint32(TR7_TRACK_MAGIC, fout);
-}
-
-static void
-tr7_wr_deinit()
-{
- gbfclose(fout);
-}
-
-static void
-tr7_write()
-{
- track_disp_all(tr7_disp_track_head_cb, nullptr, tr7_disp_waypt_cb);
-}
-
-/**************************************************************************/
-
-ff_vecs_t mapasia_tr7_vecs = { /* we can read and write tracks */
- ff_type_file,
- {
- ff_cap_none /* waypoints */,
- (ff_cap)(ff_cap_read | ff_cap_write) /* tracks */,
- ff_cap_none /* routes */
- },
- tr7_rd_init,
- tr7_wr_init,
- tr7_rd_deinit,
- tr7_wr_deinit,
- tr7_read,
- tr7_write,
- nullptr,
- &tr7_args,
- CET_CHARSET_UTF8, 1 /* FIXED - CET-REVIEW - */
- , NULL_POS_OPS
-};
-
-/**************************************************************************/
+++ /dev/null
-/*
- Copyright (C) 2014 Robert Lipe
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
- */
-#include "mapfactor.h"
-
-#include <QByteArray> // for QByteArray
-#include <QIODevice> // for QIODevice, operator|, QIODevice::ReadOnly, QIODevice::Text, QIODevice::WriteOnly
-#include <QtGlobal> // for qPrintable
-#include <QStringLiteral> // for QStringLiteral
-#include <QXmlStreamAttributes> // for QXmlStreamAttributes
-#include <QXmlStreamReader> // for QXmlStreamReader, QXmlStreamReader::EndElement, QXmlStreamReader::StartElement
-#include <QXmlStreamWriter> // for QXmlStreamWriter
-
-#include "defs.h" // for Waypoint, fatal, waypt_add, waypt_disp_all
-#include "src/core/file.h" // for File
-#include "src/core/xmlstreamwriter.h" // for XmlStreamWriter
-
-
-#define MYNAME "mapfactor"
-
-void MapfactorFormat::MapfactorRead()
-{
- Waypoint* wpt = nullptr;
-
- while (!reader.atEnd()) {
- auto tag_name = reader.name();
- if (reader.tokenType()==QXmlStreamReader::StartElement) {
- if (tag_name == u"item") {
- wpt = new Waypoint;
-
- QXmlStreamAttributes a = reader.attributes();
- wpt->shortname = a.value("name").toString();
- wpt->latitude = a.value("lat").toDouble() / milliarcseconds;
- wpt->longitude = a.value("lon").toDouble() / milliarcseconds;
- }
- }
-
- if (reader.tokenType() == QXmlStreamReader::EndElement) {
- if (wpt && reader.name() == u"item") {
- waypt_add(wpt);
- }
- }
-
- reader.readNext();
- }
-}
-
-void
-MapfactorFormat::rd_init(const QString& fname)
-{
- mapfactor_read_fname = fname;
-}
-
-void
-MapfactorFormat::read()
-{
- gpsbabel::File file(mapfactor_read_fname);
- file.open(QIODevice::ReadOnly);
- reader.setDevice(&file);
-
- MapfactorRead();
- if (reader.hasError()) {
- fatal(MYNAME ":Read error: %s (%s, line %ld, col %ld)\n",
- qPrintable(reader.errorString()),
- qPrintable(file.fileName()),
- (long) reader.lineNumber(),
- (long) reader.columnNumber());
- }
-}
-
-void
-MapfactorFormat::wr_init(const QString& fname)
-{
- oqfile = new gpsbabel::File(fname);
- oqfile->open(QIODevice::WriteOnly | QIODevice::Text);
- writer = new gpsbabel::XmlStreamWriter(oqfile);
-
- writer->setAutoFormatting(true);
- writer->setAutoFormattingIndent(2);
- writer->writeStartDocument();
-}
-
-void
-MapfactorFormat::wr_deinit()
-{
- writer->writeEndDocument();
- delete writer;
- writer = nullptr;
- oqfile->close();
- delete oqfile;
- oqfile = nullptr;
-}
-
-void
-MapfactorFormat::mapfactor_waypt_pr(const Waypoint* waypointp) const
-{
- writer->writeStartElement(QStringLiteral("item"));
-
- writer->writeAttribute(QStringLiteral("name"), waypointp->shortname);
- writer->writeAttribute(QStringLiteral("lat"), QString::number(waypointp->latitude * milliarcseconds, 'f', 0));
- writer->writeAttribute(QStringLiteral("lon"), QString::number(waypointp->longitude * milliarcseconds, 'f', 0));
- writer->writeEndElement();
-}
-
-void
-MapfactorFormat::write()
-{
- writer->writeStartElement(QStringLiteral("favourites"));
- writer->writeAttribute(QStringLiteral("version"), QStringLiteral("1"));
- // TODO: This could be moved to wr_init, but the pre GPX version put the two
- // lines above this, so mimic that behaviour exactly.
- writer->setAutoFormatting(true);
- auto mapfactor_waypt_pr_lambda = [this](const Waypoint* waypointp)->void {
- mapfactor_waypt_pr(waypointp);
- };
- waypt_disp_all(mapfactor_waypt_pr_lambda);
- writer->writeEndElement();
-}
+++ /dev/null
-/*
- Copyright (C) 2014 Robert Lipe
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
- */
-#ifndef MAPFACTOR_H_INCLUDED_
-#define MAPFACTOR_H_INCLUDED_
-
-#include <QString> // for QString
-#include <QVector> // for QVector
-#include <QXmlStreamReader> // for QXmlStreamReader
-#include <QXmlStreamWriter> // for QXmlStreamWriter
-
-#include "defs.h" // for ff_cap, arglist_t, ff_cap_none, CET_CHARSET_UTF8, Waypoint, ff_cap_read, ff_cap_write, ff_type, ff_type_file
-#include "format.h" // for Format
-#include "src/core/file.h" // for File
-
-
-class MapfactorFormat : public Format
-{
-public:
- QVector<arglist_t>* get_args() override
- {
- return &mapfactor_args;
- }
-
- ff_type get_type() const override
- {
- return ff_type_file;
- }
-
- QVector<ff_cap> get_cap() const override
- {
- /* waypoints, tracks, routes */
- return { (ff_cap)(ff_cap_read | ff_cap_write), ff_cap_none, ff_cap_none };
- }
-
- QString get_encode() const override
- {
- return CET_CHARSET_UTF8;
- }
-
- int get_fixed_encode() const override
- {
- return 0;
- }
-
- void rd_init(const QString& fname) override;
- void read() override;
- void wr_init(const QString& fname) override;
- void write() override;
- void wr_deinit() override;
-
-private:
- /* Constants */
-
- static constexpr double milliarcseconds = 60.0 * 60.0 * 1000.0;
-
- /* Member Functions */
-
- void MapfactorRead();
- void mapfactor_waypt_pr(const Waypoint* waypointp) const;
-
- /* Data Members */
-
- gpsbabel::File* oqfile{};
- QXmlStreamWriter* writer{};
-
- QVector<arglist_t> mapfactor_args = {
- };
-
- QXmlStreamReader reader;
- QString mapfactor_read_fname;
-};
-#endif // MAPFACTOR_H_INCLUDED_
+++ /dev/null
-/*
-
- Support for Memory-Map Navigator Overlay Files (.mmo)
-
- Copyright (C) 2008 Olaf Klein, o.b.klein@gpsbabel.org
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
- */
-
-#include <cassert> // for assert
-#include <cctype> // for isspace
-#include <cerrno> // for errno
-#include <cstdio> // for SEEK_CUR, fprintf, size_t, stdout
-#include <cstdlib> // for abort, strtol
-#include <cstdint>
-#include <cstring> // for strcmp, strlen, memset, strchr, strncmp
-#include <ctime>
-
-#include <QByteArray> // for QByteArray
-#include <QChar> // for operator==, QChar
-#include <QDateTime> // for QDateTime
-#include <QHash> // for QHash, QHash<>::const_iterator
-#include <QLatin1String> // for QLatin1String
-#include <QScopedPointer> // for QScopedPointer
-#include <QString> // for QString, operator==
-#include <QTextCodec> // for QTextCodec, QTextCodec::IgnoreHeader
-#include <QTextEncoder> // for QTextEncoder
-#include <QVector> // for QVector
-#include <Qt> // for CaseInsensitive
-#include <QtGlobal> // for qAsConst, QAddConst<>::Type, foreach, Q_UNUSED
-
-#include "defs.h"
-#include "gbfile.h" // for gbfputc, gbfgetuint16, gbfgetc, gbfgetdbl, gbfgetuint32, gbfputflt, gbfputuint32, gbfgetint16, gbfputdbl, gbfputuint16, gbfclose, gbfread, gbfseek, gbfputint16, gbfwrite, gbfcopyfrom, gbfeof, gbfgetflt, gbfgetint32, gbfile, gbfopen, gbfrewind, gbsize_t
-#include "session.h" // for curr_session, session_t
-#include "src/core/datetime.h" // for DateTime
-
-
-#define MYNAME "mmo"
-
-// #define MMO_DBG
-
-static char* opt_locked, *opt_visible, *opt_version;
-
-static
-QVector<arglist_t> mmo_args = {
- {
- "locked", &opt_locked, "Write items 'locked' [default no]", "0",
- ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
- },
- {
- "visible", &opt_visible, "Write items 'visible' [default yes]", "1",
- ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
- },
- {
- "ver", &opt_version, "Write files with internal version [n]", nullptr,
- ARGTYPE_INT, "17", "18", nullptr
- },
-};
-
-struct mmo_data_t {
- int objid; /* internal object id */
- const char* name;
- const char* category; /* currently not handled */
- gpsdata_type type; /* type of "data" */
- time_t ctime;
- time_t mtime;
- int left; /* number of unread route points */
- void* data; /* can be a waypoint, a route or a track */
- int refct;
- mmo_data_t** members;
- unsigned char visible:1;
- unsigned char locked:1;
- unsigned char loaded:1;
-};
-
-static gbfile* fin, *fout;
-static QTextCodec* utf16le_codec{nullptr};
-static QTextCodec* legacy_codec{nullptr};
-static int mmo_version;
-static int mmo_obj_ct;
-static int mmo_object_id;
-static uint32_t mmo_filemark;
-static uint16_t wpt_object_id;
-static uint16_t rte_object_id;
-static uint16_t trk_object_id;
-static uint16_t cat_object_id;
-static uint16_t ico_object_id;
-static uint16_t pos_object_id;
-static uint16_t txt_object_id;
-static gpsdata_type mmo_datatype;
-static const route_head* mmo_rte;
-
-static QHash<QString, int> category_names;
-static QHash<int, QString> icons;
-static QHash<int, mmo_data_t*> objects;
-static QHash<QString, unsigned> mmobjects;
-
-struct mmo_icon_mapping_t {
- int value;
- const char* icon;
-};
-
-/* standard icons; no bitmaps in file */
-
-static const mmo_icon_mapping_t mmo_icon_value_table[] = {
- { 0x00, "Dot" },
- { 0x01, "House" },
- { 0x02, "Fuel" },
- { 0x03, "Car" },
- { 0x04, "Fish" },
- { 0x05, "Boat" },
- { 0x06, "Anchor" },
- { 0x07, "Wreck" },
- { 0x08, "Exit" },
- { 0x09, "Skull" },
- { 0x0A, "Flag" },
- { 0x0B, "Camp" },
- { 0x0C, "Man Overboard" },
- { 0x0D, "Deer" },
- { 0x0E, "First Aid" },
- { 0x0F, "Trackback" },
- { 0x10, "Tiny dot" },
- { 0x11, "Triangle" },
- { 0x12, "Square" },
- { 0x13, "Circle" },
- { 0x14, "Green buoy" },
- { 0x15, "Red buoy" },
- { 0x16, "Yellow buoy" },
- { 0x17, "Geocache" },
-
- { -1, nullptr }
-};
-
-static const uint32_t obj_type_ico = 0x00;
-static const uint32_t obj_type_rte = 0x14;
-static const uint32_t obj_type_trk = 0x1E;
-#ifdef MMO_DBG
-static const uint32_t obj_type_txt = 0x32;
-#endif
-static const uint32_t obj_type_wpt = 0x3C;
-
-/* helpers */
-
-#ifdef MMO_DBG
-static void
-dbgprintf(const char* sobj, const char* fmt, ...)
-{
- va_list args;
- va_start(args, fmt);
-
- printf(MYNAME "-%s: ", sobj);
- vprintf(fmt, args);
- va_end(args);
-}
-
-# define DBG(args) dbgprintf args
-#else
-# define DBG(args) do {} while (0) ;
-#endif
-
-static QString
-mmo_readstr()
-{
- QString res;
-
- signed int len = (unsigned)gbfgetc(fin);
- if (len == 0xFF) {
- // Next two bytes are either the length (strings longer than 254 chars)
- // or FE then FF (which is -2) meaning a UTF-16 string
- len = gbfgetint16(fin);
- if (len == -2) {
- // read the new length (single byte)
- // length is number of "characters" not number of bytes
- len = (unsigned)gbfgetc(fin);
- if (len > 0) {
- QByteArray bytesin = gbfreadbuf(len*2, fin);
- res = utf16le_codec->toUnicode(bytesin);
- return res;
- }
- // length zero is handled below: returns an empty string
- } else if (len < 0) {
- fatal(MYNAME ": Invalid string length (%d)!\n", len);
- }
- // positive values of len are for strings longer than 254, handled below:
- }
- // length zero returns an empty string
- if (len) {
- QByteArray bytesin = gbfreadbuf(len, fin);
- res = legacy_codec->toUnicode(bytesin);
- }
-
- return res;
-}
-
-
-static int
-mmo_fillbuf2(void* buf, const gbsize_t bufsz, const gbsize_t count, const int need_all)
-{
- if (count > (unsigned int)bufsz) {
- fatal(MYNAME ": Internal error (bufsz too small)!\n");
- }
-
- memset(buf, 0xFF, count);
- gbsize_t res = gbfread(buf, 1, count, fin);
- if (need_all && (res < count)) {
- fatal(MYNAME ": Unexpected end of file!\n");
- }
-
- return res;
-}
-#define mmo_fillbuf(a,b,c) mmo_fillbuf2((a),sizeof((a)),(b),(c))
-
-#ifdef MMO_DBG
-static void
-mmo_printbuf(const char* buf, int count, const char* comment)
-{
- int i;
- printf("%s", comment);
- for (i = 0; i < count; i++) {
- printf("%02X ", buf[i] & 0xFF);
- }
- printf("- ");
- for (i = 0; i < count; i++)
- if (isprint(buf[i])) {
- printf("%c", buf[i] & 0xFF);
- } else {
- printf(".");
- }
- printf("\n");
- fflush(stdout);
-}
-#endif
-
-/******************************************************************************/
-
-static mmo_data_t*
-mmo_register_object(const int objid, const void* ptr, const gpsdata_type type)
-{
- auto* data = (mmo_data_t*) xcalloc(1, sizeof(mmo_data_t));
- data->data = const_cast<void*>(ptr);
- data->visible = 1;
- data->locked = 0;
- data->type = type;
- data->objid = objid;
-
- objects.insert(objid, data);
-
- return data;
-}
-
-
-static int
-mmo_get_objid(const void* ptr)
-{
- for (auto o = objects.constBegin(); o != objects.constEnd(); ++o) {
- if (o.value()->data == ptr) {
- return o.key();
- }
- }
- return 0;
-}
-
-
-static mmo_data_t*
-mmo_get_object(const uint16_t objid)
-{
- int key = objid | 0x8000;
- if (!objects.contains(key)) {
-#ifdef MMO_DBG
- gbfseek(fin, -2, SEEK_CUR);
- int ni, n;
- for (ni = 0; (n = gbfgetc(fin)) != EOF; ni++) {
- DBG(("mmo_get_object", "%04X %02X %c (%d)\n",
- ni, n, n >= 32 && n <= 126 ? (char)n : '.', n));
- }
-#endif
- fatal(MYNAME ": Unregistered object id 0x%04X!\n", objid | 0x8000);
- }
-
- return objects.value(key);
-}
-
-static Waypoint*
-mmo_get_waypt(mmo_data_t* data)
-{
- data->refct++;
- if (data->refct == 1) {
- return static_cast<Waypoint*>(data->data);
- } else {
- return new Waypoint(*(Waypoint*)data->data);
- }
-}
-
-static void
-mmo_free_object(mmo_data_t* data)
-{
- if (data->name) {
- xfree(data->name);
- }
- if ((data->type == wptdata) && (data->refct == 0)) {
- delete (Waypoint*)data->data;
- }
- xfree(data);
-}
-
-
-static void
-mmo_register_icon(const int id, const char* name)
-{
- icons.insert(id, QString::fromUtf8(name));
-}
-
-
-static mmo_data_t* mmo_read_object();
-
-
-static void
-mmo_end_of_route(mmo_data_t* data)
-{
- auto* rte = (route_head*) data->data;
-
- if (mmo_version >= 0x12) {
-#ifdef MMO_DBG
- const char* sobj = "CObjRoute";
-#endif
- char buf[7];
-
- mmo_fillbuf(buf, 7, 1);
- DBG((sobj, "route data (since 0x12): "));
-#ifdef MMO_DBG
- mmo_printbuf(buf, 7, "");
-#endif
- rte->line_color.bbggrr = le_read32(&buf[0]);
- rte->line_color.opacity = 255 - (buf[6] * 51);
- DBG((sobj, "color = 0x%06X\n", rte->line_color.bbggrr));
- DBG((sobj, "transparency = %d (-> %d)\n", buf[6], rte->line_color.opacity));
- DBG((sobj, "for \"%s\" \n", data->name));
- }
-
- if (rte->rte_waypt_ct() == 0) { /* don't keep empty routes */
- route_del_head(rte);
- data->data = nullptr;
- }
-}
-
-
-static void
-mmo_read_category(mmo_data_t* data)
-{
- int marker = gbfgetuint16(fin);
-
- if (marker & 0x8000) {
- DBG(("mmo_read_category", "reading category object\n"));
- gbfseek(fin, -2, SEEK_CUR);
- mmo_data_t* tmp = mmo_read_object();
- if (data) {
- data->category = tmp->name;
- }
- }
-}
-
-
-static void
-mmo_read_CObjIcons(mmo_data_t* data)
-{
- Q_UNUSED(data);
-#ifdef MMO_DBG
- const char* sobj = "CObjIcons";
-#endif
- int icon_id;
- uint16_t u16;
-
- DBG((sobj, ":-----------------------------------------------------\n"));
- DBG((sobj, "name = \"%s\" [ visible=%s, id=0x%04X ]\n",
- data->name, data->visible ? "yes" : "NO", data->objid));
-
- if (mmo_version >= 0x18) {
- u16 = gbfgetuint16(fin);
- DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
- u16 = gbfgetuint16(fin);
- DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
- u16 = gbfgetuint16(fin);
- DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
- u16 = gbfgetuint16(fin);
- DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
- }
- u16 = gbfgetuint16(fin);
- (void) u16;
- DBG((sobj, "unknown value = 0x%04X\n", u16));
- u16 = gbfgetuint16(fin);
- DBG((sobj, "unknown value = 0x%04X\n", u16));
- u16 = gbfgetuint16(fin);
- DBG((sobj, "unknown value = 0x%04X\n", u16));
-
- while ((icon_id = gbfgetuint32(fin))) {
- (void) gbfgetuint32(fin);
- (void) gbfgetuint32(fin);
- QString name = mmo_readstr();
- DBG((sobj, "bitmap(0x%08X) = \"%s\"\n", icon_id, qPrintable(name)));
- mmo_register_icon(icon_id, CSTR(name));
- // The next four bytes hold the length of the image,
- // read them and then skip the image data.
- gbfseek(fin, gbfgetuint32(fin), SEEK_CUR);
- }
-}
-
-
-static void
-mmo_read_CObjWaypoint(mmo_data_t* data)
-{
-#ifdef MMO_DBG
- const char* sobj = "CObjWaypoint";
-#endif
- Waypoint* wpt;
- mmo_data_t** rtelink = nullptr;
- char buf[16];
- int i;
-
- DBG((sobj, ":-----------------------------------------------------\n"));
- DBG((sobj, "name = \"%s\" [ visible=%s, id=0x%04X ]\n",
- data->name, data->visible ? "yes" : "NO", data->objid));
-
- data->data = wpt = new Waypoint;
- wpt->shortname = data->name;
-
- time_t time = data->mtime;
- if (! time) {
- time = data->ctime;
- }
- if (time > 0) {
- wpt->SetCreationTime(time);
- }
-
- if (mmo_version >= 0x18) {
- uint16_t u16 = gbfgetuint16(fin);
- DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
- u16 = gbfgetuint16(fin);
- DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
- u16 = gbfgetuint16(fin);
- DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
- u16 = gbfgetuint16(fin);
- DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
- (void) u16;
- }
-
- wpt->latitude = gbfgetdbl(fin);
- wpt->longitude = gbfgetdbl(fin);
-
- DBG((sobj, "trackpoint %d/%d coordinates = %f / %f\n", ctp+1,tp, wpt->latitude, wpt->longitude));
-
- int rtelinks = gbfgetuint16(fin);
- if (rtelinks > 0) {
-
- rtelink = (mmo_data_t**) xcalloc(sizeof(*rtelink), rtelinks);
- DBG((sobj, "rtelinks = %d\n", rtelinks));
-
- for (i = 0; i < rtelinks; i++) {
- DBG((sobj, "read rtelink number %d\n", i + 1));
- rtelink[i] = mmo_read_object();
- }
-
- }
-
- QString str = mmo_readstr(); /* descr + url */
- if (str.startsWith("_FILE_ ")) {
- str.remove(0,7);
- str = str.trimmed();
- int index = str.indexOf('\n');
-
- QString url = str.mid(0, index).trimmed();
- if (!url.isEmpty()) {
- wpt->AddUrlLink(url);
- }
-
- if (index > 0) {
- str.remove(0,index + 1);
- if (!str.isEmpty()) {
- wpt->notes = str;
- }
- }
-
- if (wpt->HasUrlLink()) {
- DBG((sobj, "url = \"%s\"\n", wpt->url));
- }
- } else if (!str.isEmpty()) {
- wpt->notes = str;
- }
- if (!wpt->notes.isEmpty()) {
- DBG((sobj, "notes = \"%s\"\n", qPrintable(wpt->notes)));
- }
-
- mmo_fillbuf(buf, 12, 1);
- i = le_read32(&buf[8]); /* icon */
- if (i != -1) {
- if (icons.contains(i)) {
- wpt->icon_descr = icons.value(i);
- DBG((sobj, "icon = \"%s\"\n", qPrintable(wpt->icon_descr)));
- }
-#ifdef MMO_DBG
- else {
- DBG((sobj, "icon not found for 0x%08X\n", i));
- }
-#endif
- }
-
- wpt->proximity = le_read_float(&buf[4]);
- if (wpt->proximity) {
- wpt->wpt_flags.proximity = 1;
- DBG((sobj, "proximity = %f\n", wpt->proximity));
- }
-
- str = mmo_readstr(); /* name on gps ??? option ??? */
- if (!str.isEmpty()) {
- wpt->description = wpt->shortname;
- wpt->shortname = str;
- DBG((sobj, "name on gps = %s\n", qPrintable(str)));
- }
-
- int ux = gbfgetuint32(fin);
- DBG((sobj, "proximity type = %d\n", ux));
- (void) ux;
-
- data->loaded = 1;
-
- if (rtelink) {
- xfree(rtelink);
- } else {
- waypt_add(mmo_get_waypt(data));
- }
-}
-
-
-static void
-mmo_read_CObjRoute(mmo_data_t* data)
-{
-#ifdef MMO_DBG
- const char* sobj = "CObjRoute";
-#endif
- route_head* rte;
-
- DBG((sobj, ":-----------------------------------------------------\n"));
- DBG((sobj, "name = \"%s\" [ visible=%s, id=0x%04X ]\n",
- data->name, data->visible ? "yes" : "NO", data->objid));
-
- data->data = rte = new route_head;
- rte->rte_name = data->name;
- route_add_head(rte);
-
- if (mmo_version >= 0x18) {
- uint16_t u16 = gbfgetuint16(fin);
- DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
- u16 = gbfgetuint16(fin);
- DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
- u16 = gbfgetuint16(fin);
- DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
- u16 = gbfgetuint16(fin);
- DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
- (void) u16;
- }
-
- int ux = gbfgetc(fin); /* line label */
- DBG((sobj, "line label = %d\n", ux));
- (void) ux;
-
- data->left = gbfgetint16(fin);
-
- if (data->left <= 0) {
- if (mmo_version >= 0x12) {
- char buf[16];
- mmo_fillbuf(buf, 7, 1);
- }
- route_del_head(rte);
- data->data = nullptr;
-
- return;
- }
-
- while (data->left > 0) {
- DBG((sobj, "read next waypoint\n"));
- mmo_data_t* tmp = mmo_read_object();
- if (tmp && tmp->data && (tmp->type == wptdata)) {
- Waypoint* wpt;
-
- /* FIXME: At this point this waypoint maybe not fully loaded (initialized) !!!
- We need a final procedure to handle this !!! */
- if (! tmp->loaded) {
- wpt = new Waypoint;
- wpt->latitude = 0;
- wpt->longitude = 0;
- xasprintf(&wpt->shortname, "\01%p", tmp);
- } else {
- wpt = mmo_get_waypt(tmp);
- }
-
- route_add_wpt(rte, wpt);
- data->left--;
- }
- }
-
- if (mmo_version > 0x11) {
- mmo_end_of_route(data);
- }
-}
-
-
-static void
-mmo_read_CObjTrack(mmo_data_t* data)
-{
-#ifdef MMO_DBG
- const char* sobj = "CObjTrack";
-#endif
-
- DBG((sobj, ":-----------------------------------------------------\n"));
- DBG((sobj, "name = \"%s\" [ visible=%s, id=0x%04X ]\n",
- data->name, data->visible ? "yes" : "NO", data->objid));
-
- auto* trk = new route_head;
- trk->rte_name = data->name;
- track_add_head(trk);
-
- if (mmo_version >= 0x18) {
- uint16_t u16 = gbfgetuint16(fin);
- DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
- u16 = gbfgetuint16(fin);
- DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
- u16 = gbfgetuint16(fin);
- DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
- u16 = gbfgetuint16(fin);
- DBG((sobj, "unknown value = 0x%04X (since 0x18)\n", u16));
- Q_UNUSED(u16);
- }
-
- int tp = gbfgetint16(fin);
- DBG((sobj, "track has %d point(s)\n", tp));
-
- for (int ctp = 0; ctp < tp; ctp++) {
- auto* wpt = new Waypoint;
-
- wpt->latitude = gbfgetdbl(fin);
- wpt->longitude = gbfgetdbl(fin);
- DBG((sobj, "coordinates = %f / %f\n", wpt->latitude, wpt->longitude));
- char unk = gbfgetc(fin);
- DBG((sobj, "Unknown = 0x%02X (%d)\n", unk, unk));
-
- wpt->SetCreationTime(gbfgetint32(fin));
- wpt->altitude = gbfgetflt(fin);
-
- if (unk != 0) {
- uint16_t ux = gbfgetuint16(fin);
- DBG((sobj, "unknown value = 0x%04X (%d)\n", ux, ux));
- Q_UNUSED(ux);
- if (unk > 1) {
- uint16_t unknown;
- unknown = gbfgetuint16(fin);
- DBG((sobj, "unknown value = 0x%04X (%d)\n", unknown, unknown));
- Q_UNUSED(unknown);
- }
- }
- track_add_wpt(trk, wpt);
- }
-
- if (mmo_version > 0) {
- uint32_t u32 = gbfgetuint32(fin); /* Min. update interval */
- DBG((sobj, "min. update interval = %d\n", u32));
- u32 = gbfgetuint32(fin); /* unknown */
- DBG((sobj, "unknown value = 0x%08X (%d)\n", u32, u32));
- u32 = gbfgetuint32(fin); /* unknown */
- DBG((sobj, "unknown value = 0x%08X (%d)\n", u32, u32));
- u32 = gbfgetuint32(fin); /* unknown */
- DBG((sobj, "min. update distance = %d\n", u32));
- u32 = gbfgetuint32(fin); /* unknown */
- DBG((sobj, "track partition interval = %d\n", u32 / 60));
- u32 = gbfgetuint32(fin); /* unknown */
- DBG((sobj, "unknown value = 0x%08X (%d)\n", u32, u32));
- u32 = gbfgetuint32(fin); /* unknown */
- DBG((sobj, "tick interval = %d\n", u32 / 60));
- trk->line_color.bbggrr = gbfgetuint32(fin); /* rgb color */
- trk->line_color.opacity = 255;
- DBG((sobj, "color = 0x%06X\n", trk->line_color.bbggrr));
- Q_UNUSED(u32);
- }
-
- if (mmo_version >= 0x12) {
- char u8 = gbfgetc(fin);
- DBG((sobj, "line width = %d - (since 0x12)\n", u8));
- u8 = gbfgetc(fin);
- DBG((sobj, "line style = %d - (since 0x12)\n", u8));
- u8 = gbfgetc(fin);
- DBG((sobj, "transparency = %d - (since 0x12)\n", u8));
- trk->line_color.opacity = 255 - (u8 * 51);
-
- if (mmo_version >= 0x16) {
- // XXX ARB was u8 = gbfgetc(fin); but actually a string
- // Don't construct a QString we aren't going to use.
- // avoid clazy-unused-non-trivial-variable
-#ifdef MMO_DBG
- QString text =
-#else
- (void)
-#endif
- mmo_readstr();
- DBG((sobj, "text = \"%s\"\n", qPrintable(text)));
- uint16_t u16 = gbfgetuint16(fin);
- DBG((sobj, "unknown value = 0x%04X (since 0x16)\n", u16));
- u16 = gbfgetuint16(fin);
- DBG((sobj, "unknown value = 0x%04X (since 0x16)\n", u16));
- Q_UNUSED(u16);
- }
- }
-
- if (trk->rte_waypt_ct() == 0) {
- track_del_head(trk);
- data->data = nullptr;
- }
-}
-
-
-static void
-mmo_read_CObjText(mmo_data_t*)
-{
-#ifdef MMO_DBG
- const char* sobj = "CObjText";
-#endif
- char buf[28];
-
- DBG((sobj, ":-----------------------------------------------------\n"));
- DBG((sobj, "name = \"%s\" [ visible=%s, id=0x%04X ]\n",
- data->name, data->visible ? "yes" : "NO", data->objid));
-
- double lat = gbfgetdbl(fin);
- double lon = gbfgetdbl(fin);
- DBG((sobj, "coordinates = %f / %f\n", lat, lon));
- Q_UNUSED(lat);
- Q_UNUSED(lon);
-
- // Don't construct a QString we aren't going to use.
- // avoid clazy-unused-non-trivial-variable
-#ifdef MMO_DBG
- QString text =
-#else
- (void)
-#endif
- mmo_readstr();
- DBG((sobj, "text = \"%s\"\n", qPrintable(text)));
-
- mmo_fillbuf(buf, 28, 1);
-
- // Don't construct a QString we aren't going to use.
- // avoid clazy-unused-non-trivial-variable
-#ifdef MMO_DBG
- QString font =
-#else
- (void)
-#endif
- mmo_readstr();
- DBG((sobj, "font = \"%s\"\n", qPrintable(font)));
-
- mmo_fillbuf(buf, 25, 1);
-}
-
-
-static void
-mmo_read_CObjCurrentPosition(mmo_data_t*)
-{
-#ifdef MMO_DBG
- const char* sobj = "CObjCurrentPosition";
-#endif
- char buf[24];
-
- DBG((sobj, ":-----------------------------------------------------\n"));
- DBG((sobj, "name = \"%s\" [ visible=%s, id=0x%04X ]\n",
- data->name, data->visible ? "yes" : "NO", data->objid));
-
- double lat = gbfgetdbl(fin);
- double lon = gbfgetdbl(fin);
- DBG((sobj, "coordinates = %f / %f\n", lat, lon));
- Q_UNUSED(lat);
- Q_UNUSED(lon);
-
- mmo_fillbuf(buf, 24, 1);
- if (mmo_version >= 0x18) {
- mmo_fillbuf(buf, 8, 1); // XXX ARB read an extra 8
- }
-
- if (mmo_version >= 0x14) {
- QString name = mmo_readstr();
- DBG((sobj, "name = \"%s\"\n", qPrintable(name)));
- // XXX ARB was just: mmo_fillbuf(buf, 13, 1);
- // but actually it's string/long/string/long/long
- (void) gbfgetuint32(fin);
- name = mmo_readstr();
- DBG((sobj, "name = \"%s\"\n", qPrintable(name)));
- (void) gbfgetuint32(fin);
- (void) gbfgetuint32(fin);
- }
-}
-
-
-static mmo_data_t*
-mmo_read_object()
-{
- mmo_data_t* data = nullptr;
-
- // There are three cases:
- // a new object of a type that has not occurred previously in this file;
- // a new object; or
- // a back reference to an object that appears earlier in the file.
-
- int objid = gbfgetuint16(fin);
- if (objid == 0xFFFF) {
- DBG(("mmo_read_object", "Registering new object type\n"));
-
- objid = mmo_object_id++;
-
- uint16_t version = gbfgetuint16(fin);
- if (version != mmo_version) {
- fatal(MYNAME ": Invalid version identifier!\n");
- }
-
- int len = gbfgetint16(fin);
-
- char* sobj = (char*) xmalloc(len + 1);
- sobj[len] = '\0';
- gbfread(sobj, len, 1, fin);
- DBG(("mmo_read_object", "%s\n", sobj));
-
- if (strcmp(sobj, "CObjIcons") == 0) {
- ico_object_id = objid;
- } else if (strcmp(sobj, "CCategory") == 0) {
- cat_object_id = objid;
- } else if (strcmp(sobj, "CObjWaypoint") == 0) {
- wpt_object_id = objid;
- } else if (strcmp(sobj, "CObjRoute") == 0) {
- rte_object_id = objid;
- } else if (strcmp(sobj, "CObjTrack") == 0) {
- trk_object_id = objid;
- } else if (strcmp(sobj, "CObjCurrentPosition") == 0) {
- pos_object_id = objid;
- } else if (strcmp(sobj, "CObjText") == 0) {
- txt_object_id = objid;
- } else {
- fatal(MYNAME ": Unknown Object \"%s\"!\n", sobj);
- }
- xfree(sobj);
- }
-
- DBG(("mmo_read_object", "objid = 0x%04X\n", objid));
-
- if (objid & 0x8000) {
- data = mmo_register_object(mmo_object_id++, nullptr, (gpsdata_type)0);
- data->name = xstrdup(mmo_readstr());
-
- if (objid != cat_object_id) {
- data->ctime = gbfgetuint32(fin);
- data->mtime = gbfgetuint32(fin);
- data->locked = gbfgetc(fin);
- data->visible = gbfgetc(fin);
-
- uint32_t obj_type = gbfgetuint32(fin);
- (void) obj_type;
-#ifdef MMO_DBG
- uint32_t expected_type = 0xFFFFFFFF;
- if (objid == ico_object_id) {
- expected_type = obj_type_ico;
- } else if (objid == trk_object_id) {
- expected_type = obj_type_trk;
- } else if (objid == wpt_object_id) {
- expected_type = obj_type_wpt;
- } else if (objid == rte_object_id) {
- expected_type = obj_type_rte;
- } else if (objid == txt_object_id) {
- expected_type = obj_type_txt;
- }
- if (mmo_version >= 0x18) {
- expected_type <<= 24;
- }
- DBG(("mmo_read_object", "object type = 0x%08X\n", obj_type));
- if (obj_type != expected_type) {
- DBG(("mmo_read_object", " expected 0x%08X\n", expected_type));
- }
-#endif
-
- if (objid != ico_object_id) {
- mmo_read_category(data);
- }
- DBG(("mmo_read_object", "Category : %s\n",
- data->category ? data->category : "[No category]"));
- }
-
- if (objid == cat_object_id) ; /* do nothing */
- else if (objid == ico_object_id) {
- mmo_read_CObjIcons(data);
- } else if (objid == trk_object_id) {
- data->type = trkdata;
- mmo_read_CObjTrack(data);
- } else if (objid == wpt_object_id) {
- data->type = wptdata;
- mmo_read_CObjWaypoint(data);
- } else if (objid == rte_object_id) {
- data->type = rtedata;
- mmo_read_CObjRoute(data);
- } else if (objid == pos_object_id) {
- mmo_read_CObjCurrentPosition(data);
- } else if (objid == txt_object_id) {
- mmo_read_CObjText(data);
- } else {
- fatal(MYNAME ": Unregistered Object-ID 0x%04X\n", objid);
- }
- } else {
- data = mmo_get_object(objid);
- }
-
- return data;
-}
-
-static void
-mmo_finalize_rtept_cb(const Waypoint* wptref)
-{
- auto* wpt = const_cast<Waypoint*>(wptref);
-
- if ((wpt->shortname[0] == '\01') && (wpt->latitude == 0) && (wpt->longitude == 0)) {
- mmo_data_t* data;
- Waypoint* wpt2;
-
-// This code path isn't tested in anything we have and I have No Idea
-// what it was trying to do. Throw a hard error to force the hand of
-// getting a sample file.
- abort();
-#if OLD
- sscanf(wpt->shortname + 1, "%p", &data);
-#endif
- wpt2 = (Waypoint*)data->data;
-
- wpt->latitude = wpt2->latitude;
- wpt->longitude = wpt2->longitude;
- wpt->shortname = wpt2->shortname;
-
- wpt->description = wpt2->description;
- wpt->notes = (wpt2->notes);
- if (wpt2->HasUrlLink()) {
- UrlLink l = wpt2->GetUrlLink();
- wpt->notes = l.url_;
- }
-
- wpt->proximity = wpt2->proximity;
- wpt->wpt_flags.proximity = wpt2->wpt_flags.proximity;
-
- if (!wpt2->icon_descr.isNull()) {
- wpt->icon_descr = wpt2->icon_descr;
- }
- }
-}
-
-/*******************************************************************************
-* %%% global callbacks called by gpsbabel main process %%% *
-*******************************************************************************/
-
-static void
-mmo_rd_init(const QString& fname)
-{
- fin = gbfopen_le(fname, "rb", MYNAME);
-
- utf16le_codec = QTextCodec::codecForName("UTF-16LE");
- legacy_codec = QTextCodec::codecForName("Windows-1252");
-
- ico_object_id = pos_object_id = txt_object_id = cat_object_id = 0;
- wpt_object_id = rte_object_id = trk_object_id = 0;
-
- mmo_object_id = 0x8001;
-
- int i = 0;
- while (mmo_icon_value_table[i].icon) {
- mmo_register_icon(mmo_icon_value_table[i].value, mmo_icon_value_table[i].icon);
- i++;
- }
-}
-
-
-static void
-mmo_rd_deinit()
-{
- route_disp_session(curr_session(), nullptr, nullptr, mmo_finalize_rtept_cb);
-
- icons.clear();
-
- for (auto* value : qAsConst(objects)) {
- mmo_free_object(value);
- }
- objects.clear();
-
- legacy_codec = nullptr;
- utf16le_codec = nullptr;
-
- gbfclose(fin);
-}
-
-
-static void
-mmo_read()
-{
-#ifdef MMO_DBG
- const char* sobj = "main";
-#endif
-
- /* copy file to memory stream (needed for seek-ops and piped commands) */
-
- DBG(("main", "loading file \"%s\".\n", fin->name));
-
- gbfile* fx = gbfopen(nullptr, "wb", MYNAME);
- gbfcopyfrom(fx, fin, 0x7FFFFFFF);
- gbfrewind(fx);
- gbfclose(fin);
- fin = fx;
-
- mmo_obj_ct = gbfgetuint16(fin);
- DBG((sobj, "number of objects = %d\n", mmo_obj_ct));
-
- int i = gbfgetuint16(fin);
- if (i != 0xFFFF) {
- fatal(MYNAME ": Marker not equal to 0xFFFF!\n");
- }
-
- mmo_version = gbfgetuint16(fin);
- DBG((sobj, "version = 0x%02X\n", mmo_version));
-
- mmo_filemark = 0xFFFF0000UL | be_read16(&mmo_version);
- DBG((sobj, "filemark = 0x%08X\n", mmo_filemark));
-
- gbfseek(fin, -4, SEEK_CUR);
-
- while (! gbfeof(fin)) { /* main read loop */
-
- (void) mmo_read_object();
-
- }
-
-#ifdef MMO_DBG
- printf("\n" MYNAME ":---------------------------------------\n");
- printf(MYNAME ": EOF reached, nice!!!\n");
- printf(MYNAME ": =======================================\n\n");
-#endif
-}
-
-/**************************************************************************/
-
-static void
-mmo_register_category_names(const QString& name)
-{
- category_names.insert(name, mmo_object_id);
-}
-
-
-static void
-mmo_writestr(const QString& str)
-{
-
- bool topbitset = false;
-
- // see if there's any utf-8 multi-byte chars
- const QByteArray utf8 = str.toUtf8();
- int len = utf8.size();
- for (unsigned char byte : utf8) {
- if (byte & 0x80) {
- topbitset = true;
- break;
- }
- }
- // Old version can't handle utf-16
- // XXX ARB check which version number can, just guessed at 0x12
- if (mmo_version < 0x12) {
- topbitset = false;
- }
-
- QByteArray outbytes;
- if (topbitset) {
- // Use an encoder to avoid generating a BOM.
- QScopedPointer<QTextEncoder> encoder(utf16le_codec->makeEncoder(QTextCodec::IgnoreHeader));
- outbytes = encoder->fromUnicode(str);
- assert(outbytes.size() % 2 == 0);
- len = outbytes.size() / 2;
- len = len & 0xff;
- } else {
- outbytes = legacy_codec->fromUnicode(str);
- len = outbytes.size();
- }
-
- // XXX ARB need to convert UTF-8 into UTF-16
- if (topbitset) {
- gbfputc(0xFF, fout); // means two-byte length follows
- gbfputc(0xFE, fout); // means utf-16 little-endian string follows
- gbfputc(0xFF, fout); // ditto
- gbfputc(len, fout);
- } else if (len > 254) {
- len = len & 0x7FFF;
- gbfputc(0xFF, fout); // means two-byte length follows
- gbfputint16(len, fout);
- } else {
- gbfputc(len, fout);
- }
- if (len) {
- if (topbitset) {
- gbfwrite(outbytes, 1, len*2, fout);
- } else {
- gbfwrite(outbytes, 1, len, fout);
- }
- }
-}
-
-static void
-mmo_enum_waypt_cb(const Waypoint*)
-{
- mmo_obj_ct++;
-}
-
-
-static void
-mmo_enum_route_cb(const route_head* rte)
-{
- if (rte->rte_waypt_ct() > 0) {
- mmo_obj_ct++;
- }
-}
-
-
-static int
-mmo_write_obj_mark(const char* sobj, const char* name)
-{
- QString key = QString::fromUtf8(sobj);
-
- if (mmobjects.contains(key)) {
- uint16_t nr = mmobjects.value(key);
- gbfputuint16(nr, fout);
- } else {
- mmo_object_id++;
-
- DBG(("write", "object \"%s\", registered type \"%s\" (id = 0x%04X)\n",
- name, sobj, mmo_object_id));
-
- mmobjects.insert(key, mmo_object_id);
-
- gbfputuint32(mmo_filemark, fout);
- gbfputuint16(strlen(sobj), fout);
- gbfwrite(sobj, strlen(sobj), 1, fout);
- }
-
- mmo_object_id++;
- int res = mmo_object_id;
- mmo_writestr(name);
-
- return res;
-}
-
-
-static void
-mmo_write_category(const char* sobj, const char* name)
-{
- QString key = QString::fromUtf8(name);
-
- if (category_names.contains(key)) {
- uint16_t nr = category_names.value(key);
- gbfputuint16(nr & 0x7FFF, fout);
- } else {
- mmo_write_obj_mark(sobj, name);
- mmo_register_category_names(key);
- }
-}
-
-
-static int
-mmo_write_obj_head(const char* sobj, const char* name, const time_t ctime,
- const uint32_t obj_type)
-{
- int res = mmo_write_obj_mark(sobj, name);
-
- gbfputuint32(ctime, fout);
- gbfputuint32(ctime, fout);
-
- gbfputc(*opt_locked, fout);
- gbfputc(*opt_visible, fout);
-
- gbfputuint32(obj_type, fout);
-
- return res;
-}
-
-
-static void
-mmo_write_wpt_cb(const Waypoint* wpt)
-{
- QString str;
- int icon = 0;
-
- time_t time = wpt->GetCreationTime().toTime_t();
- if (time < 0) {
- time = 0;
- }
-
- if (mmo_datatype == trkdata) {
- gbfputdbl(wpt->latitude, fout);
- gbfputdbl(wpt->longitude, fout);
- gbfputc(0, fout);
- gbfputuint32(time, fout);
- if (wpt->altitude != unknown_alt) {
- gbfputflt(wpt->altitude, fout);
- } else {
- gbfputflt(0, fout);
- }
-
- return;
- }
-
- DBG(("write", "waypoint \"%s\"\n", wpt->shortname ? wpt->shortname : "Mark"));
- int objid = mmo_write_obj_head("CObjWaypoint",
- wpt->shortname.isEmpty() ? "Mark" : CSTR(wpt->shortname), time, obj_type_wpt);
- mmo_data_t* data = mmo_register_object(objid, wpt, wptdata);
- data->refct = 1;
- mmo_write_category("CCategory", (mmo_datatype == rtedata) ? "Waypoints" : "Marks");
-
- gbfputdbl(wpt->latitude, fout);
- gbfputdbl(wpt->longitude, fout);
-
- if (mmo_datatype == rtedata) {
- int i = mmo_get_objid(mmo_rte);
- gbfputuint16(1, fout); /* two extra bytes */
- gbfputuint16(i & 0x7FFF, fout);
- } else {
- gbfputuint16(0, fout); /* extra bytes */
- }
-
- if (wpt->HasUrlLink()) {
- str = "_FILE_ ";
- UrlLink l = wpt->GetUrlLink();
- str += l.url_;
- str += "\n";
- }
-
- QString cx = wpt->notes;
- if (cx == nullptr) {
- cx = wpt->description;
- }
- if (cx != nullptr) {
- char* kml = nullptr;
-
- if (wpt->session->name == QLatin1String("kml")) {
- utf_string tmp(true, cx);
- cx = kml = strip_html(&tmp);
- }
- str += cx;
- if (kml) {
- xfree(kml);
- }
- }
- mmo_writestr(str);
-
- gbfputuint32(0x01, fout);
- if WAYPT_HAS(wpt, proximity) {
- gbfputflt((int) wpt->proximity, fout);
- } else {
- gbfputflt(0, fout);
- }
-
- if (!wpt->icon_descr.isNull()) {
- int i = 0;
-
- while (mmo_icon_value_table[i].icon) {
- if (wpt->icon_descr.compare(mmo_icon_value_table[i].icon, Qt::CaseInsensitive) == 0) {
- icon = mmo_icon_value_table[i].value;
- break;
- }
- i++;
- }
- }
- gbfputuint32(icon, fout);
-
- mmo_writestr(""); /* name on gps */
- gbfputuint32(0x00, fout);
-}
-
-
-static void
-mmo_write_rte_head_cb(const route_head* rte)
-{
- time_t time = 0x7FFFFFFF;
-
- if (rte->rte_waypt_ct() <= 0) {
- return;
- }
-
- mmo_rte = rte;
-
- foreach (const Waypoint* wpt, rte->waypoint_list) {
- gpsbabel::DateTime t = wpt->GetCreationTime();
- if ((t.isValid()) && (t.toTime_t() < time)) {
- time = t.toTime_t();
- }
- }
- if (time == 0x7FFFFFFF) {
- time = gpsbabel_time;
- }
- int objid = mmo_write_obj_head("CObjRoute",
- rte->rte_name.isEmpty() ? "Route" : CSTR(rte->rte_name), time, obj_type_rte);
- mmo_register_object(objid, rte, rtedata);
- mmo_write_category("CCategory", "Route");
- gbfputc(0, fout); /* unknown */
- gbfputuint16(rte->rte_waypt_ct(), fout);
-}
-
-
-static void
-mmo_write_rte_tail_cb(const route_head* rte)
-{
- if (rte->rte_waypt_ct() <= 0) {
- return;
- }
-
- DBG(("write", "route with %d point(s).\n", rte->rte_waypt_ct()));
-
- if (mmo_version >= 0x12) {
- if (rte->line_color.bbggrr < 0) {
- gbfputuint32(0xFF, fout); /* color; default red */
- gbfputc(0x01, fout); /* Line width "normal" */
- gbfputc(0x00, fout); /* Line style "solid"*/
- gbfputc(0x00, fout); /* Transparency "Opaque" */
- } else {
- gbfputuint32(rte->line_color.bbggrr, fout); /* color */
- gbfputc(0x01, fout); /* Line width "normal" */
- gbfputc(0x00, fout); /* Line style "solid"*/
- gbfputc((255 - rte->line_color.opacity) / 51, fout); /* Transparency "Opaque" */
- }
- }
-
- foreach (const Waypoint* wpt, rte->waypoint_list) {
- int objid = mmo_get_objid(wpt);
- gbfputuint16(objid & 0x7FFF, fout);
- }
-}
-
-
-static void
-mmo_write_trk_head_cb(const route_head* trk)
-{
- if (trk->rte_waypt_ct() <= 0) {
- return;
- }
- int objid = mmo_write_obj_head("CObjTrack",
- trk->rte_name.isEmpty() ? "Track" : CSTR(trk->rte_name), gpsbabel_time, obj_type_trk);
-
- mmo_write_category("CCategory", "Track");
- gbfputuint16(trk->rte_waypt_ct(), fout);
-
- mmo_register_object(objid, trk, trkdata);
-}
-
-
-static void
-mmo_write_trk_tail_cb(const route_head* trk)
-{
- if (trk->rte_waypt_ct() <= 0) {
- return;
- }
-
- gbfputuint32(0x0A, fout); /* Min. update interval */
- gbfputflt(0, fout);
- gbfputflt(0, fout);
- gbfputuint32(0x0F, fout); /* Min. update distance */
- gbfputuint32(0xE10, fout); /* Track partition interval */
- gbfputuint32(0x00, fout); /* ??? */
- gbfputuint32(0x12C, fout);
-
- if (trk->line_color.bbggrr < 0) {
- gbfputuint32(0xFF0000, fout); /* color; default blue */
- if (mmo_version >= 0x12) {
- gbfputc(0x01, fout); /* Line width "normal" */
- gbfputc(0x00, fout); /* Line style "solid"*/
- gbfputc(0x00, fout); /* Transparency "Opaque" */
- }
- } else {
- gbfputuint32(trk->line_color.bbggrr, fout); /* color */
- if (mmo_version >= 0x12) {
- gbfputc(0x01, fout); /* Line width "normal" */
- gbfputc(0x00, fout); /* Line style "solid"*/
- gbfputc((255 - trk->line_color.opacity) / 51, fout); /* Transparency "Opaque" */
- }
- }
-}
-
-/**************************************************************************/
-
-static void
-mmo_wr_init(const QString& fname)
-{
- fout = gbfopen_le(fname, "wb", MYNAME);
-
- utf16le_codec = QTextCodec::codecForName("UTF-16LE");
- legacy_codec = QTextCodec::codecForName("Windows-1252");
-
- mmo_object_id = 0x8000;
- mmo_obj_ct = 1; /* ObjIcons always present */
- mmo_version = 0x12; /* by default we write as version 0x12 */
- if (opt_version) {
- while (isspace(*opt_version)) {
- opt_version++;
- }
- errno = 0;
- mmo_version = strtol(opt_version, nullptr, 0);
- if (errno || ((mmo_version != 0x11) && (mmo_version != 0x12))) {
- fatal(MYNAME ": Unsupported version identifier (%s)!\n", opt_version);
- }
- }
- DBG(("write", "version = 0x%02X\n", mmo_version));
- mmo_filemark = 0xFFFFUL | (mmo_version << 16);
-}
-
-
-static void
-mmo_wr_deinit()
-{
- mmobjects.clear();
- category_names.clear();
-
- for (auto* value : qAsConst(objects)) {
- mmo_free_object(value);
- }
- objects.clear();
-
- legacy_codec = nullptr;
- utf16le_codec = nullptr;
-
- gbfclose(fout);
-}
-
-
-static void
-mmo_write()
-{
- /* find out number of objects we have to write */
- waypt_disp_all(mmo_enum_waypt_cb);
- route_disp_all(mmo_enum_route_cb, nullptr, mmo_enum_waypt_cb);
- track_disp_all(mmo_enum_route_cb, nullptr, nullptr);
-
- gbfputuint16(mmo_obj_ct, fout);
-
- mmo_write_obj_head("CObjIcons", "Unnamed object", gpsbabel_time, obj_type_ico);
- for (int i = 0; i < 5; i++) {
- gbfputuint16(0, fout);
- }
-
- mmo_datatype = wptdata;
- waypt_disp_all(mmo_write_wpt_cb);
- mmo_datatype = rtedata;
- route_disp_all(mmo_write_rte_head_cb, mmo_write_rte_tail_cb, mmo_write_wpt_cb);
- mmo_datatype = trkdata;
- track_disp_all(mmo_write_trk_head_cb, mmo_write_trk_tail_cb, mmo_write_wpt_cb);
-}
-
-/**************************************************************************/
-
-ff_vecs_t mmo_vecs = {
- ff_type_file,
- FF_CAP_RW_ALL, /* read and write waypoints, tracks and routes*/
- mmo_rd_init,
- mmo_wr_init,
- mmo_rd_deinit,
- mmo_wr_deinit,
- mmo_read,
- mmo_write,
- nullptr,
- &mmo_args,
- CET_CHARSET_MS_ANSI, 0
- , NULL_POS_OPS
-};
-
-/**************************************************************************/
+++ /dev/null
-/*
-
-Format converter for MediaTek Locus-capable devices.
-
-Copyright (C) 2012 Jeremy Mortis, mortis@tansay.ca
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
--------------------------------------------------------------------
-
-This module will download logged track data (a.k.a. Locus) from a GPS
-devices based on the MediaTek MT3339 GPS chipset, such as:
-- GlobalTop PA6H Module
-- Fastrax IT530
-
-The MT3339 also emits standard NMEA packets including
-$GPGGA, $GPGSA, $GPGSV, $GPRMC, and $GPVTG. This module ignores those.
-If you have an MT3339 and you want to process NMEA packets, simply use
-the nmea format instead of this one.
-
-Example usage::
-# Read from USB port, output trackpoints in GPX format
-./gpsbabel -t -i mtk_locus -f /dev/ttyUSB0 -o gpx -F out.gpx
-
-*/
-
-
-#include "defs.h"
-#include "gbser.h"
-#include <cerrno>
-#include <cstdio>
-#include <cstdlib>
-
-static route_head* track;
-
-static char* opt_baudrate;
-static char* opt_download;
-static char* opt_erase;
-static char* opt_status;
-static char* opt_enable;
-
-static QVector<arglist_t> mtk_locus_args = {
- {"baudrate", &opt_baudrate, "Speed in bits per second of serial port (autodetect=0)", "0", ARGTYPE_INT, ARG_NOMINMAX , nullptr},
- {"download", &opt_download, "Download logged fixes", "1", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr },
- {"erase", &opt_erase, "Erase device data after download", "0", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr },
- {"status", &opt_status, "Show device status", "0", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr },
- {"enable", &opt_enable, "Enable logging after download", "0", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr },
-};
-
-static void mtk_locus_rd_init(const QString& fname);
-static void mtk_locus_rd_deinit();
-static void mtk_locus_read();
-
-ff_vecs_t mtk_locus_vecs = {
- ff_type_file,
- {
- ff_cap_read /* waypoints */,
- ff_cap_read /* tracks */,
- ff_cap_none /* routes */
- },
- mtk_locus_rd_init,
- nullptr, // write init
- mtk_locus_rd_deinit,
- nullptr, // write deinit
- mtk_locus_read,
- nullptr, // write
- nullptr, // exit
- &mtk_locus_args,
- CET_CHARSET_ASCII, 0 /* ascii is the expected character set */
- , NULL_POS_OPS
-};
-
-#define MYNAME "mtk_locus"
-#define TIMEOUT 1500
-
-#define PMTK_ACK "$PMTK001"
-#define PMTK_LOCUS_STOP_LOGGER "$PMTK185"
-#define PMTK_LOCUS_QUERY_STATUS "$PMTK183"
-#define PMTK_LOCUS_ERASE_FLASH "$PMTK184"
-#define PMTK_Q_LOCUS_DATA "$PMTK622"
-#define PMTK_Q_RELEASE "$PMTK605"
-#define PMTK_DT_RELEASE "$PMTK705"
-
-static gbfile* ffd; // File access.
-static void* sfd;
-static enum {rm_serial, rm_file} read_mode;
-static int packetnum;
-static char line[1000];
-static int download_complete;
-static int valid_packet_found;
-static int fixes_found;
-static int first_loxsequence;
-static int last_loxsequence;
-static char waiting_for[20];
-
-
-static void set_baudrate();
-static void read_line();
-static void process_packet();
-static void process_pmtklox();
-static void process_pmtklog();
-static void process_pmtk001();
-static void process_pmtk705();
-static void send_command(const char* s, const char*wait_for);
-static int calculate_checksum(const char* s, int length);
-static void dbg(int l, const char* msg, ...);
-
-static void
-mtk_locus_rd_init(const QString& fname)
-{
- dbg(1, "Opening file: %s\n", qPrintable(fname));
-
- if (gbser_is_serial(qPrintable(fname))) {
-
- dbg(1, "Input is a serial port\n");
- read_mode = rm_serial;
- if ((sfd = gbser_init(qPrintable(fname))) == nullptr) {
- fatal(MYNAME ": Can't initialise port \"%s\" (%s)\n", qPrintable(fname), strerror(errno));
- }
- set_baudrate();
- gbser_flush(sfd);
-
- } else {
-
- dbg(1, "Input is a normal file\n");
- read_mode = rm_file;
- if ((ffd = gbfopen(fname, "rb", MYNAME)) == nullptr) {
- fatal(MYNAME ": Can't initialise port \"%s\" (%s)\n", qPrintable(fname), strerror(errno));
- }
- }
-
- dbg(1, "File opened\n");
-}
-
-static void
-mtk_locus_rd_deinit()
-{
- if (read_mode == rm_serial) {
- gbser_deinit(sfd);
- } else {
- gbfclose(ffd);
- }
-}
-
-static void
-mtk_locus_read()
-{
- track = new route_head;
- track_add_head(track);
- dbg(1, "Track initialized\n");
-
- packetnum = 0;
- valid_packet_found = 0;
- fixes_found = 0;
- download_complete = 0;
- first_loxsequence = -1;
- last_loxsequence = -1;
-
- read_line();
- // initial serial buffer may contain garbage, so read until valid packet found
- for (int i = 0; i<10; i++) {
- process_packet();
- read_line();
- if (valid_packet_found) {
- break;
- }
- }
-
- if (! valid_packet_found) {
- fatal(MYNAME "No valid input data found");
- }
-
- if (strcmp(opt_download, "1") == 0) {
- send_command(PMTK_Q_LOCUS_DATA ",1", nullptr);
-
- while (! download_complete) {
- process_packet();
- read_line();
- }
- }
-
- if (read_mode == rm_serial) {
- if (strcmp(opt_erase, "1") == 0) {
- send_command(PMTK_LOCUS_ERASE_FLASH ",1", PMTK_ACK);
- printf("Flash erased\n");
- }
-
- if (strcmp(opt_enable, "1") == 0) {
- send_command(PMTK_LOCUS_STOP_LOGGER ",0", PMTK_ACK);
- printf("Logging enabled\n");
- } else {
- send_command(PMTK_LOCUS_STOP_LOGGER ",1", PMTK_ACK);
- printf("Logging disabled\n");
- }
-
- if (strcmp(opt_status, "1") == 0) {
- printf("Device status:\n");
- send_command(PMTK_Q_RELEASE, PMTK_DT_RELEASE);
- send_command(PMTK_LOCUS_QUERY_STATUS, PMTK_ACK);
- }
- }
-}
-
-void
-set_baudrate()
-{
- int rc;
- int baudrates[] = { 4800, 9600, 14400, 19200, 38400, 57600, 115200, 0 };
- int baudrate;
-
- if (strcmp(opt_baudrate, "0") != 0) {
-
- baudrate = atoi(opt_baudrate);
- rc = gbser_set_speed(sfd, baudrate);
- if (rc != gbser_OK) {
- fatal(MYNAME ": Set baud rate to %i failed (%i)\n", baudrate, rc);
- }
-
- } else {
-
- dbg(1, "Probing for baudrate...\n");
- for (int i=0;; i++) {
- baudrate = baudrates[i];
- if (baudrate == 0) {
- fatal(MYNAME ": Autobaud connection failed\n");
- }
- dbg(1, MYNAME ": Probing at %i baud...\n", baudrate);
- rc = gbser_set_speed(sfd, baudrate);
-
- if (rc != gbser_OK) {
- dbg(1, "Set speed failed\n");
- continue;
- }
-
- rc = gbser_read_line(sfd, line, sizeof(line)-1, TIMEOUT, 0x0A, 0x0D);
- if (rc != gbser_OK) {
- dbg(1, "Read test failed\n");
- continue;
- }
-
- dbg(1, "Port successfully opened\n");
- break;
- }
- }
-}
-
-void
-read_line()
-{
- line[0] = '\0';
-
- if (read_mode == rm_file) {
- char* s = gbfgetstr(ffd);
- if (s == nullptr) {
- dbg(1, "EOF reached\n");
- download_complete = 1;
- return;
- }
- strncat(line, s, sizeof(line)-1);
- } else {
- int rc = gbser_read_line(sfd, line, sizeof(line)-1, TIMEOUT, 0x0A, 0x0D);
- if (rc != gbser_OK) {
- fatal(MYNAME "Serial read failed: %i\n", rc);
- }
- }
-
- packetnum++;
- dbg(1, "Line %i: %s\n", packetnum, line);
-}
-
-void
-process_packet()
-{
- int given_checksum;
-
- if ((strlen(line) < 3) || (line[0] != '$') || (line[strlen(line)-3] != '*')) {
- dbg(1, "Line %i: Malformed packet\n", packetnum);
- return;
- }
-
- int calculated_checksum = calculate_checksum(&line[1], strlen(line) - 1 - 3);
- sscanf(&line[strlen(line) - 2], "%02x", &given_checksum);
- if (calculated_checksum != given_checksum) {
- dbg(1, "Line %i: NMEA Checksum incorrect, expecting %02X\n", packetnum, calculated_checksum);
- return;
- }
-
- if (strncmp(line, waiting_for, strlen(waiting_for)) == 0) {
- waiting_for[0] = '\0';
- }
-
- valid_packet_found = 1;
- line[strlen(line) - 3] = '\0'; // remove checksum
-
- // note that use of strtok in following routines corrupts the value of line
-
- if (strncmp(line, "$PMTKLOX", 8) == 0) {
- process_pmtklox();
- } else if (strncmp(line, "$PMTKLOG", 8) == 0) {
- process_pmtklog();
- } else if (strncmp(line, "$PMTK001", 8) == 0) {
- process_pmtk001();
- } else if (strncmp(line, "$PMTK705", 8) == 0) {
- process_pmtk705();
- } else {
- dbg(1, "Unknown packet type\n");
- }
-
-}
-
-void
-process_pmtklox()
-{
- uint8_t fixbytes[16];
- static Waypoint* trkpt;
- static Waypoint* waypt;
-
- char* token = strtok(line, ",");
- if ((token == nullptr) || (strcmp(token, "$PMTKLOX") != 0)) {
- warning("Line %i: Invalid packet id\n", packetnum);
- return;
- }
-
- char* loxtype = strtok(nullptr, ",");
- if (loxtype == nullptr) {
- warning("Line %i: Missing lox type\n", packetnum);
- return;
- }
-
- if (strcmp(loxtype, "0") == 0) {
- last_loxsequence = atoi(strtok(nullptr, "*")) - 1;
- dbg(1, "Line %i: last sequence will be %i\n", packetnum, last_loxsequence);
- return;
- }
-
- if (strcmp(loxtype, "2") == 0) {
- printf("Found %i fixes\n", fixes_found);
- download_complete = 1;
- return;
- }
-
- if (strcmp(loxtype, "1") != 0) {
- dbg(1, "Line %i: Invalid lox type\n", packetnum);
- return;
- }
-
- int loxsequence = atoi(strtok(nullptr, ","));
-
- if (first_loxsequence == -1) {
- first_loxsequence = loxsequence;
- if (first_loxsequence != 0) {
- fatal(MYNAME "Dump already in progress (first $PMTKLOX has sequence %i)\n", first_loxsequence);
- }
- }
-
- if (read_mode == rm_serial) {
- printf("Downloading packet %i of %i\r", loxsequence, last_loxsequence);
- }
-
- token = strtok(nullptr, ",");
- int fixnum = 0;
- while (token != nullptr) {
- fixnum++;
- int bytenum = 0;
- uint8_t calculated_checksum = 0;
- for (int wordnum = 0; wordnum<4; wordnum++) { // 4 8-byte hex strings per fix
- if (token == nullptr) {
- dbg(1, "Line %i: Fix %i incomplete data\n", packetnum, fixnum);
- return;
- }
- for (int i = 0; i<4; i++) {
- unsigned int hexval;
- sscanf(&token[i * 2], "%2x", &hexval);
- fixbytes[bytenum++] = hexval;
- calculated_checksum ^= hexval;
- }
- token = strtok(nullptr, ",");
- }
-
- if (calculated_checksum != 0) {
- dbg(1, "Line %i: Fix %i failed checksum\n", packetnum, fixnum);
- continue;
- }
-
- uint32_t timestamp = le_read32(&fixbytes[0]);
- char fixtype = fixbytes[4];
- float latitude = le_read_float(&fixbytes[5]);
- float longitude = le_read_float(&fixbytes[9]);
- int height = le_read16(&fixbytes[13]);
-
- if (fixtype != '\x02') {
- dbg(1, "line %i: Fix %i Invalid fix type: %02X\n", packetnum, fixnum, fixtype);
- continue;
- }
-
- if ((latitude < -180.0) || (latitude > 180.0)
- || (longitude < -180.0) || (longitude > 180.0)
- || (height < -1000) || (height > 100000)) {
- dbg(1, "line %i: Fix %i data out of range\n", packetnum, fixnum);
- continue;
- }
-
- if (global_opts.masked_objective & TRKDATAMASK) {
- trkpt = new Waypoint;
- trkpt->SetCreationTime(timestamp);
- trkpt->latitude = latitude;
- trkpt->longitude = longitude;
- trkpt->altitude = height;
- trkpt->sat = 0;
- trkpt->hdop = 0;
- trkpt->fix = fix_3d;
- track_add_wpt(track, trkpt);
- }
-
- if (global_opts.masked_objective & WPTDATAMASK) {
- waypt = new Waypoint;
- waypt->SetCreationTime(timestamp);
- waypt->latitude = latitude;
- waypt->longitude = longitude;
- waypt->altitude = height;
- waypt->sat = 0;
- waypt->hdop = 0;
- waypt->fix = fix_3d;
- waypt_add(waypt);
- }
-
- dbg(1, "Time: %li Type: %02x Lat: %f Long: %f height: %i\n", (long int)timestamp, fixtype, latitude, longitude, height);
-
- fixes_found++;
- }
-}
-
-void
-process_pmtklog()
-{
- strtok(line, ",");
-
- printf("Serial#: %s\n", strtok(nullptr, ","));
-
- int type = atoi(strtok(nullptr, ","));
- if (type == 0) {
- printf("Type: %i (wrap around when full)\n", type);
- } else {
- printf("Type: %i (stop when full)\n", type);
- }
-
- printf("Mode: 0x%02X\n", atoi(strtok(nullptr, ",")));
- printf("Content: %s\n", strtok(nullptr, ","));
- printf("Interval: %s seconds\n", strtok(nullptr, ","));
- printf("Distance: %s\n", strtok(nullptr, ","));
- printf("Speed: %s\n", strtok(nullptr, ","));
-
- int status = atoi(strtok(nullptr, ","));
- if (status == 0) {
- printf("Status: %i (enabled)\n", status);
- } else {
- printf("Status: %i (disabled)\n", status);
- }
-
- printf("Number: %s fixes available\n", strtok(nullptr, ","));
- printf("Percent: %s%% used\n", strtok(nullptr, ","));
-}
-
-void
-process_pmtk001()
-{
- strtok(line, ",");
- char* cmd = strtok(nullptr,",");
- char* flag = strtok(nullptr,",");
-
- switch (atoi(flag)) {
- case 0:
- dbg(1, "Ack: %s %s (Invalid command)\n", cmd, flag);
- break;
- case 1:
- dbg(1, "Ack: %s %s (Unsupported command)\n", cmd, flag);
- break;
- case 2:
- dbg(1, "Ack: %s %s (Action failed)\n", cmd, flag);
- break;
- case 3:
- dbg(1, "Ack: %s %s (Success)\n", cmd, flag);
- break;
- default:
- dbg(1, "Ack: %s %s (Unknown error)\n", cmd, flag);
- break;
- }
-}
-
-void
-process_pmtk705()
-{
- char* token = strtok(line, ",");
- token = strtok(nullptr,",");
-
- printf("Firmware: %s\n", token);
-}
-
-void
-send_command(const char* s, const char* wait_for)
-{
- time_t starttime;
- time_t currtime;
- char cmd[100];
-
- if (read_mode == rm_file) {
- dbg(1, "Sending device commands ignored when using file input: %s\n", s);
- return;
- }
-
- int checksum = calculate_checksum(&s[1], strlen(s)-1);
- snprintf(cmd, sizeof(cmd)-1, "%s*%02X\r\n", s, checksum);
-
- int rc = gbser_print(sfd, cmd);
- if (rc != gbser_OK) {
- fatal(MYNAME ": Write error (%d)\n", rc);
- }
-
- dbg(1, "Sent command: %s\n", cmd);
-
- if (wait_for == nullptr) {
- waiting_for[0] = '\0';
- return;
- }
-
- time(&starttime);
- cmd[0] = '\0';
- strncat(cmd, &s[5], 3);
- waiting_for[0] = '\0';
- strncat(waiting_for, wait_for, sizeof(waiting_for)-1);
- dbg(1, "Waiting for: %s\n", waiting_for);
-
- read_line();
- while (strlen(waiting_for) > 0) {
- time(&currtime);
- if (currtime > starttime + 5) {
- fatal(MYNAME "Ack not received: %s\n", s);
- }
- process_packet();
- read_line();
- }
-}
-
-int
-calculate_checksum(const char* s, int length)
-{
- int sum = 0;
-
- for (int i = 0; i<length; i++) {
- sum ^= *s++;
- }
- return sum;
-}
-
-void
-dbg(int l, const char* msg, ...)
-{
- va_list ap;
- va_start(ap, msg);
- if (global_opts.debug_level >= l) {
- vfprintf(stderr,msg, ap);
- fflush(stderr);
- }
- va_end(ap);
-}
-
-
+++ /dev/null
-/*
- Handle MyNav TRC format .trc and .ftn files
-
- For information on the data format see
- http://www.mynav.it/hwdoc/dev/TRC_Format_Spec.pdf
-
- Copyright (c) 2014-2020 Ralf Horstmann <ralf@ackstorm.de>
- Copyright (C) 2014-2020 Robert Lipe, robertlipe+source@gpsbabel.org
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
- */
-
-#include <QChar>
-#include <QDebug>
-#include <QIODevice>
-#include <QString>
-#include <QStringList>
-#include <QtGlobal>
-
-#include "src/core/textstream.h"
-
-#include "mynav.h"
-
-/***************************************************************************
- * local helper functions *
- ***************************************************************************/
-
-void
-MyNavFormat::read_line(const QString& line, route_head* track)
-{
- const QStringList fields = line.split('|');
-
- if (global_opts.debug_level > 1) {
- qDebug() << "line: " << line;
- for (int i = 0; i < fields.size(); i++) {
- qDebug() << "field" << i << fields.at(i);
- }
- }
-
- // don't consider lines without latitude/longitude
- if (fields.size() <= fld_lat) {
- return;
- }
-
- // only type 1 and type 5 lines contain coordinates
- bool ok = false;
- int line_type = fields.at(fld_type).trimmed().toInt(&ok);
- if (!ok) {
- return;
- }
- if (line_type != line_sensors && line_type != line_gps) {
- return;
- }
-
- // This field is not present in .trc files, only in .ftn, so
- // ignore line if present and != 1
- if (fields.size() > fld_gps_valid) {
- int val_gps_valid = fields.at(fld_gps_valid).trimmed().toInt(&ok);
- if (!ok || val_gps_valid != 1) {
- return;
- }
- }
-
- double val_lon = fields.at(fld_lon).trimmed().toDouble(&ok) / 3600000.0;
- if (!ok) {
- return;
- }
- double val_lat = fields.at(fld_lat).trimmed().toDouble(&ok) / 3600000.0;
- if (!ok) {
- return;
- }
-
- auto* wpt = new Waypoint;
- wpt->latitude = val_lat;
- wpt->longitude = val_lon;
-
- if (fields.size() > fld_altitude) {
- double val_alt = fields.at(fld_altitude).trimmed().toDouble(&ok);
- if (ok) {
- wpt->altitude = val_alt;
- }
- }
-
- if (fields.size() > fld_timestamp) {
- int val_time = fields.at(fld_timestamp).trimmed().toInt(&ok);
- if (ok) {
- wpt->SetCreationTime(val_time);
- }
- }
-
- track_add_wpt(track, wpt);
-}
-
-/***************************************************************************
- * entry points called by gpsbabel main process *
- ***************************************************************************/
-
-void
-MyNavFormat::rd_init(const QString& fname)
-{
- read_fname = fname;
-}
-
-void
-MyNavFormat::rd_deinit()
-{
- read_fname.clear();
-}
-
-void
-MyNavFormat::read()
-{
- gpsbabel::TextStream stream;
- stream.open(read_fname, QIODevice::ReadOnly, "mynav");
-
- auto* track = new route_head;
- track_add_head(track);
-
- QString buf;
- while (stream.readLineInto(&buf)) {
- buf = buf.trimmed();
- if ((buf.isEmpty()) || buf.startsWith('#')) {
- continue;
- }
- read_line(buf, track);
- }
-
- stream.close();
-}
+++ /dev/null
-/*
- Handle MyNav TRC format .trc and .ftn files
-
- Copyright (c) 2014-2020 Ralf Horstmann <ralf@ackstorm.de>
- Copyright (C) 2014-2020 Robert Lipe, robertlipe+source@gpsbabel.org
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
- */
-
-#ifndef MYNAV_H_INCLUDED_
-#define MYNAV_H_INCLUDED_
-
-#include <QString>
-#include <QVector>
-
-#include "defs.h"
-#include "format.h"
-
-class MyNavFormat : public Format
-{
-public:
- ff_type get_type() const override
- {
- return ff_type_file;
- }
-
- QVector<ff_cap> get_cap() const override
- {
- return {
- ff_cap_none, // waypoints
- ff_cap_read, // tracks
- ff_cap_none // routes
- };
- }
-
- QString get_encode() const override
- {
- return CET_CHARSET_ASCII;
- }
-
- int get_fixed_encode() const override
- {
- return 0;
- }
-
- void rd_init(const QString& fname) override;
- void read() override;
- void rd_deinit() override;
-
-private:
- enum field_e {
- fld_type = 0,
- fld_lon,
- fld_lat,
- fld_direction,
- fld_speed,
- fld_altitude,
- fld_timestamp,
- fld_duration,
- fld_gps_valid,
- fld_distance,
- fld_ascent,
- fld_cadence,
- fld_heart_rate,
- fld_id,
- fld_total_duration,
- fld_terminator
- };
-
- enum line_e {
- line_header = 0,
- line_sensors = 1,
- line_geonote = 2,
- line_gps = 5,
- line_lap_pause = 7,
- line_lap_restart = 8,
- line_total = 9,
- line_lap_start = 10,
- line_lap_end = 11,
- };
-
- static void read_line(const QString& line, route_head* track);
-
- QString read_fname;
-
-};
-
-#endif
energympro cpo Energympro GPS training watch
enigma ert Enigma binary waypoint file (.ert)
shape shp ESRI shapefile
-f90g map F90G Automobile DVR GPS log file
igc FAI/IGC Flight Recorder Data Format
garmin_fit fit Flexible and Interoperable Data Transfer (FIT) Activity file
flysight csv FlySight GPS File
html html HTML Output
humminbird_ht ht Humminbird tracks (.ht)
humminbird hwr Humminbird waypoints and routes (.hwr)
-ignrando rdn IGN Rando track files
-igoprimo_poi upoi iGo Primo points of interest (.upoi)
-igo2008_poi upoi iGO2008 points of interest (.upoi)
-igo8 trk IGO8 .trk
-kompass_tk wp Kompass (DAV) Track (.tk)
-kompass_wp wp Kompass (DAV) Waypoints (.wp)
lowranceusr usr Lowrance USR
magellanx upt Magellan SD files (as for eXplorist)
magellan Magellan SD files (as for Meridian)
magellan Magellan serial protocol
-ik3d ikt MagicMaps IK3D project file (.ikt)
-mainnav nav Mainnav
-tef xml Map&Guide 'TourExchangeFormat' XML
-mapasia_tr7 tr7 MapAsia track file (.tr7)
-mapbar trk Mapbar (China) navigation track for Sonim Xp3300
-mapfactor xml Mapfactor Navigator
-mapconverter txt Mapopolis.com Mapconverter CSV
-mxf mxf MapTech Exchange Format
-mtk_locus MediaTek Locus
-mmo mmo Memory-Map Navigator overlay files (.mmo)
s_and_t txt Microsoft Streets and Trips 2002-2007
miniHomer MiniHomer, a skyTraq Venus 6 based logger (download tracks, waypoints and get/set POI)
garmin_xt Mobile Garmin XT Track files
-motoactv csv Motoactiv CSV
-bcr bcr Motorrad Routenplaner (Map&Guide) .bcr files
mtk-bin bin MTK Logger (iBlue 747,...) Binary File Format
mtk MTK Logger (iBlue 747,Qstarz BT-1000,...) download
-mynav trc MyNav TRC format
tpg tpg National Geographic Topo .tpg (waypoints)
tpo2 tpo National Geographic Topo 2.x .tpo
tpo3 tpo National Geographic Topo 3.x/4.x .tpo
dna dna Navitrak DNA marker format
nima NIMA/GNIS Geographic Names File
nmea NMEA 0183 sentences
-lmx Nokia Landmark Exchange
osm osm OpenStreetMap data files
ozi OziExplorer
qstarz_bl-1000 Qstarz BL-1000
file energympro cpo Energympro GPS training watch
file enigma ert Enigma binary waypoint file (.ert)
file shape shp ESRI shapefile
-file f90g map F90G Automobile DVR GPS log file
file igc FAI/IGC Flight Recorder Data Format
file garmin_fit fit Flexible and Interoperable Data Transfer (FIT) Activity file
file flysight csv FlySight GPS File
file html html HTML Output
file humminbird_ht ht Humminbird tracks (.ht)
file humminbird hwr Humminbird waypoints and routes (.hwr)
-file ignrando rdn IGN Rando track files
-file igoprimo_poi upoi iGo Primo points of interest (.upoi)
-file igo2008_poi upoi iGO2008 points of interest (.upoi)
-file igo8 trk IGO8 .trk
internal random Internal GPS data generator
-file kompass_tk wp Kompass (DAV) Track (.tk)
-file kompass_wp wp Kompass (DAV) Waypoints (.wp)
file lowranceusr usr Lowrance USR
file magellanx upt Magellan SD files (as for eXplorist)
file magellan Magellan SD files (as for Meridian)
serial magellan Magellan serial protocol
-file ik3d ikt MagicMaps IK3D project file (.ikt)
-file mainnav nav Mainnav
-file tef xml Map&Guide 'TourExchangeFormat' XML
-file mapasia_tr7 tr7 MapAsia track file (.tr7)
-file mapbar trk Mapbar (China) navigation track for Sonim Xp3300
-file mapfactor xml Mapfactor Navigator
-file mapconverter txt Mapopolis.com Mapconverter CSV
-file mxf mxf MapTech Exchange Format
-file mtk_locus MediaTek Locus
-file mmo mmo Memory-Map Navigator overlay files (.mmo)
file s_and_t txt Microsoft Streets and Trips 2002-2007
serial miniHomer MiniHomer, a skyTraq Venus 6 based logger (download tracks, waypoints and get/set POI)
file garmin_xt Mobile Garmin XT Track files
-file motoactv csv Motoactiv CSV
-file bcr bcr Motorrad Routenplaner (Map&Guide) .bcr files
file mtk-bin bin MTK Logger (iBlue 747,...) Binary File Format
serial mtk MTK Logger (iBlue 747,Qstarz BT-1000,...) download
-file mynav trc MyNav TRC format
file tpg tpg National Geographic Topo .tpg (waypoints)
file tpo2 tpo National Geographic Topo 2.x .tpo
file tpo3 tpo National Geographic Topo 3.x/4.x .tpo
file dna dna Navitrak DNA marker format
file nima NIMA/GNIS Geographic Names File
file nmea NMEA 0183 sentences
-file lmx Nokia Landmark Exchange
file osm osm OpenStreetMap data files
file ozi OziExplorer
file qstarz_bl-1000 Qstarz BL-1000
file --r--- energympro cpo Energympro GPS training watch
file ----rw enigma ert Enigma binary waypoint file (.ert)
file rwrwrw shape shp ESRI shapefile
-file --r--- f90g map F90G Automobile DVR GPS log file
file --rwrw igc FAI/IGC Flight Recorder Data Format
file -wrw-- garmin_fit fit Flexible and Interoperable Data Transfer (FIT) Activity file
file rw---- flysight csv FlySight GPS File
file -w---- html html HTML Output
file r-rwr- humminbird_ht ht Humminbird tracks (.ht)
file rwr-rw humminbird hwr Humminbird waypoints and routes (.hwr)
-file --rw-- ignrando rdn IGN Rando track files
-file rw---- igoprimo_poi upoi iGo Primo points of interest (.upoi)
-file rw---- igo2008_poi upoi iGO2008 points of interest (.upoi)
-file --rw-- igo8 trk IGO8 .trk
internal r-r-r- random Internal GPS data generator
-file --rw-- kompass_tk wp Kompass (DAV) Track (.tk)
-file rw---- kompass_wp wp Kompass (DAV) Waypoints (.wp)
file rwrwrw lowranceusr usr Lowrance USR
file rwrwrw magellanx upt Magellan SD files (as for eXplorist)
file rwrwrw magellan Magellan SD files (as for Meridian)
serial rwrwrw magellan Magellan serial protocol
-file r-r--- ik3d ikt MagicMaps IK3D project file (.ikt)
-file --rw-- mainnav nav Mainnav
-file ----r- tef xml Map&Guide 'TourExchangeFormat' XML
-file --rw-- mapasia_tr7 tr7 MapAsia track file (.tr7)
-file --r--- mapbar trk Mapbar (China) navigation track for Sonim Xp3300
-file rw---- mapfactor xml Mapfactor Navigator
-file rw---- mapconverter txt Mapopolis.com Mapconverter CSV
-file rw---- mxf mxf MapTech Exchange Format
-file r-r--- mtk_locus MediaTek Locus
-file rwrwrw mmo mmo Memory-Map Navigator overlay files (.mmo)
file rw---- s_and_t txt Microsoft Streets and Trips 2002-2007
serial r-r--- miniHomer MiniHomer, a skyTraq Venus 6 based logger (download tracks, waypoints and get/set POI)
file --r--- garmin_xt Mobile Garmin XT Track files
-file rw---- motoactv csv Motoactiv CSV
-file ----rw bcr bcr Motorrad Routenplaner (Map&Guide) .bcr files
file r-r--- mtk-bin bin MTK Logger (iBlue 747,...) Binary File Format
serial r-r--- mtk MTK Logger (iBlue 747,Qstarz BT-1000,...) download
-file --r--- mynav trc MyNav TRC format
file rw---- tpg tpg National Geographic Topo .tpg (waypoints)
file --r--- tpo2 tpo National Geographic Topo 2.x .tpo
file r-r-r- tpo3 tpo National Geographic Topo 3.x/4.x .tpo
file rw---- dna dna Navitrak DNA marker format
file rw---- nima NIMA/GNIS Geographic Names File
file rwrw-- nmea NMEA 0183 sentences
-file rw---- lmx Nokia Landmark Exchange
file rw-wrw osm osm OpenStreetMap data files
file rwrwrw ozi OziExplorer
file r-r--- qstarz_bl-1000 Qstarz BL-1000
option shape url Source for URL field in .dbf string 0 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_shape.html#fmt_shape_o_url
-file --r--- f90g map F90G Automobile DVR GPS log file f90g
- https://www.gpsbabel.org/WEB_DOC_DIR/fmt_f90g.html
file --rwrw igc FAI/IGC Flight Recorder Data Format igc
https://www.gpsbabel.org/WEB_DOC_DIR/fmt_igc.html
option igc timeadj (integer sec or 'auto') Barograph to GPS time diff string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_igc.html#fmt_igc_o_timeadj
https://www.gpsbabel.org/WEB_DOC_DIR/fmt_humminbird_ht.html
file rwr-rw humminbird hwr Humminbird waypoints and routes (.hwr) humminbird
https://www.gpsbabel.org/WEB_DOC_DIR/fmt_humminbird.html
-file --rw-- ignrando rdn IGN Rando track files ignrando
- https://www.gpsbabel.org/WEB_DOC_DIR/fmt_ignrando.html
-option ignrando index Index of track to write (if more than one in source) integer 1 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_ignrando.html#fmt_ignrando_o_index
-
-file rw---- igoprimo_poi upoi iGo Primo points of interest (.upoi) xcsv
- https://www.gpsbabel.org/WEB_DOC_DIR/fmt_igoprimo_poi.html
-option igoprimo_poi snlen Max synthesized shortname length integer 1 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_igoprimo_poi.html#fmt_igoprimo_poi_o_snlen
-
-option igoprimo_poi snwhite Allow whitespace synth. shortnames boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_igoprimo_poi.html#fmt_igoprimo_poi_o_snwhite
-
-option igoprimo_poi snupper UPPERCASE synth. shortnames boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_igoprimo_poi.html#fmt_igoprimo_poi_o_snupper
-
-option igoprimo_poi snunique Make synth. shortnames unique boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_igoprimo_poi.html#fmt_igoprimo_poi_o_snunique
-
-option igoprimo_poi urlbase Basename prepended to URL on output string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_igoprimo_poi.html#fmt_igoprimo_poi_o_urlbase
-
-option igoprimo_poi prefer_shortnames Use shortname instead of description boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_igoprimo_poi.html#fmt_igoprimo_poi_o_prefer_shortnames
-
-option igoprimo_poi datum GPS datum (def. WGS 84) string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_igoprimo_poi.html#fmt_igoprimo_poi_o_datum
-
-file rw---- igo2008_poi upoi iGO2008 points of interest (.upoi) xcsv
- https://www.gpsbabel.org/WEB_DOC_DIR/fmt_igo2008_poi.html
-option igo2008_poi snlen Max synthesized shortname length integer 1 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_igo2008_poi.html#fmt_igo2008_poi_o_snlen
-
-option igo2008_poi snwhite Allow whitespace synth. shortnames boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_igo2008_poi.html#fmt_igo2008_poi_o_snwhite
-
-option igo2008_poi snupper UPPERCASE synth. shortnames boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_igo2008_poi.html#fmt_igo2008_poi_o_snupper
-
-option igo2008_poi snunique Make synth. shortnames unique boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_igo2008_poi.html#fmt_igo2008_poi_o_snunique
-
-option igo2008_poi urlbase Basename prepended to URL on output string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_igo2008_poi.html#fmt_igo2008_poi_o_urlbase
-
-option igo2008_poi prefer_shortnames Use shortname instead of description boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_igo2008_poi.html#fmt_igo2008_poi_o_prefer_shortnames
-
-option igo2008_poi datum GPS datum (def. WGS 84) string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_igo2008_poi.html#fmt_igo2008_poi_o_datum
-
-file --rw-- igo8 trk IGO8 .trk igo8
- https://www.gpsbabel.org/WEB_DOC_DIR/fmt_igo8.html
-option igo8 tracknum Track identification number integer https://www.gpsbabel.org/WEB_DOC_DIR/fmt_igo8.html#fmt_igo8_o_tracknum
-
-option igo8 title Track title string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_igo8.html#fmt_igo8_o_title
-
-option igo8 description Track description string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_igo8.html#fmt_igo8_o_description
-
internal r-r-r- random Internal GPS data generator random
https://www.gpsbabel.org/WEB_DOC_DIR/fmt_random.html
option random points Generate # points integer 1 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_random.html#fmt_random_o_points
option random nodelay Output realtime points without delay boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_random.html#fmt_random_o_nodelay
-file --rw-- kompass_tk wp Kompass (DAV) Track (.tk) xcsv
- https://www.gpsbabel.org/WEB_DOC_DIR/fmt_kompass_tk.html
-option kompass_tk snlen Max synthesized shortname length integer 1 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_kompass_tk.html#fmt_kompass_tk_o_snlen
-
-option kompass_tk snwhite Allow whitespace synth. shortnames boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_kompass_tk.html#fmt_kompass_tk_o_snwhite
-
-option kompass_tk snupper UPPERCASE synth. shortnames boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_kompass_tk.html#fmt_kompass_tk_o_snupper
-
-option kompass_tk snunique Make synth. shortnames unique boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_kompass_tk.html#fmt_kompass_tk_o_snunique
-
-option kompass_tk urlbase Basename prepended to URL on output string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_kompass_tk.html#fmt_kompass_tk_o_urlbase
-
-option kompass_tk prefer_shortnames Use shortname instead of description boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_kompass_tk.html#fmt_kompass_tk_o_prefer_shortnames
-
-option kompass_tk datum GPS datum (def. WGS 84) string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_kompass_tk.html#fmt_kompass_tk_o_datum
-
-file rw---- kompass_wp wp Kompass (DAV) Waypoints (.wp) xcsv
- https://www.gpsbabel.org/WEB_DOC_DIR/fmt_kompass_wp.html
-option kompass_wp snlen Max synthesized shortname length integer 1 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_kompass_wp.html#fmt_kompass_wp_o_snlen
-
-option kompass_wp snwhite Allow whitespace synth. shortnames boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_kompass_wp.html#fmt_kompass_wp_o_snwhite
-
-option kompass_wp snupper UPPERCASE synth. shortnames boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_kompass_wp.html#fmt_kompass_wp_o_snupper
-
-option kompass_wp snunique Make synth. shortnames unique boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_kompass_wp.html#fmt_kompass_wp_o_snunique
-
-option kompass_wp urlbase Basename prepended to URL on output string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_kompass_wp.html#fmt_kompass_wp_o_urlbase
-
-option kompass_wp prefer_shortnames Use shortname instead of description boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_kompass_wp.html#fmt_kompass_wp_o_prefer_shortnames
-
-option kompass_wp datum GPS datum (def. WGS 84) string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_kompass_wp.html#fmt_kompass_wp_o_datum
-
file rwrwrw lowranceusr usr Lowrance USR lowranceusr
https://www.gpsbabel.org/WEB_DOC_DIR/fmt_lowranceusr.html
option lowranceusr ignoreicons (USR input) Ignore event marker icons on read boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_lowranceusr.html#fmt_lowranceusr_o_ignoreicons
option magellan nukewpt Delete all waypoints boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_magellan.html#fmt_magellan_o_nukewpt
-file r-r--- ik3d ikt MagicMaps IK3D project file (.ikt) ik3d
- https://www.gpsbabel.org/WEB_DOC_DIR/fmt_ik3d.html
-file --rw-- mainnav nav Mainnav xcsv
- https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mainnav.html
-option mainnav snlen Max synthesized shortname length integer 1 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mainnav.html#fmt_mainnav_o_snlen
-
-option mainnav snwhite Allow whitespace synth. shortnames boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mainnav.html#fmt_mainnav_o_snwhite
-
-option mainnav snupper UPPERCASE synth. shortnames boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mainnav.html#fmt_mainnav_o_snupper
-
-option mainnav snunique Make synth. shortnames unique boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mainnav.html#fmt_mainnav_o_snunique
-
-option mainnav urlbase Basename prepended to URL on output string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mainnav.html#fmt_mainnav_o_urlbase
-
-option mainnav prefer_shortnames Use shortname instead of description boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mainnav.html#fmt_mainnav_o_prefer_shortnames
-
-option mainnav datum GPS datum (def. WGS 84) string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mainnav.html#fmt_mainnav_o_datum
-
-file ----r- tef xml Map&Guide 'TourExchangeFormat' XML tef
- https://www.gpsbabel.org/WEB_DOC_DIR/fmt_tef.html
-option tef routevia Include only via stations in route boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_tef.html#fmt_tef_o_routevia
-
-file --rw-- mapasia_tr7 tr7 MapAsia track file (.tr7) mapasia_tr7
- https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mapasia_tr7.html
-file --r--- mapbar trk Mapbar (China) navigation track for Sonim Xp3300 mapbar
- https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mapbar.html
-file rw---- mapfactor xml Mapfactor Navigator mapfactor
- https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mapfactor.html
-file rw---- mapconverter txt Mapopolis.com Mapconverter CSV xcsv
- https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mapconverter.html
-option mapconverter snlen Max synthesized shortname length integer 1 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mapconverter.html#fmt_mapconverter_o_snlen
-
-option mapconverter snwhite Allow whitespace synth. shortnames boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mapconverter.html#fmt_mapconverter_o_snwhite
-
-option mapconverter snupper UPPERCASE synth. shortnames boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mapconverter.html#fmt_mapconverter_o_snupper
-
-option mapconverter snunique Make synth. shortnames unique boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mapconverter.html#fmt_mapconverter_o_snunique
-
-option mapconverter urlbase Basename prepended to URL on output string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mapconverter.html#fmt_mapconverter_o_urlbase
-
-option mapconverter prefer_shortnames Use shortname instead of description boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mapconverter.html#fmt_mapconverter_o_prefer_shortnames
-
-option mapconverter datum GPS datum (def. WGS 84) string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mapconverter.html#fmt_mapconverter_o_datum
-
-file rw---- mxf mxf MapTech Exchange Format xcsv
- https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mxf.html
-option mxf snlen Max synthesized shortname length integer 1 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mxf.html#fmt_mxf_o_snlen
-
-option mxf snwhite Allow whitespace synth. shortnames boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mxf.html#fmt_mxf_o_snwhite
-
-option mxf snupper UPPERCASE synth. shortnames boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mxf.html#fmt_mxf_o_snupper
-
-option mxf snunique Make synth. shortnames unique boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mxf.html#fmt_mxf_o_snunique
-
-option mxf urlbase Basename prepended to URL on output string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mxf.html#fmt_mxf_o_urlbase
-
-option mxf prefer_shortnames Use shortname instead of description boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mxf.html#fmt_mxf_o_prefer_shortnames
-
-option mxf datum GPS datum (def. WGS 84) string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mxf.html#fmt_mxf_o_datum
-
-file r-r--- mtk_locus MediaTek Locus mtk_locus
- https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mtk_locus.html
-option mtk_locus baudrate Speed in bits per second of serial port (autodetect=0) integer 0 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mtk_locus.html#fmt_mtk_locus_o_baudrate
-
-option mtk_locus download Download logged fixes boolean 1 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mtk_locus.html#fmt_mtk_locus_o_download
-
-option mtk_locus erase Erase device data after download boolean 0 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mtk_locus.html#fmt_mtk_locus_o_erase
-
-option mtk_locus status Show device status boolean 0 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mtk_locus.html#fmt_mtk_locus_o_status
-
-option mtk_locus enable Enable logging after download boolean 0 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mtk_locus.html#fmt_mtk_locus_o_enable
-
-file rwrwrw mmo mmo Memory-Map Navigator overlay files (.mmo) mmo
- https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mmo.html
-option mmo locked Write items 'locked' [default no] boolean 0 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mmo.html#fmt_mmo_o_locked
-
-option mmo visible Write items 'visible' [default yes] boolean 1 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mmo.html#fmt_mmo_o_visible
-
-option mmo ver Write files with internal version [n] integer 17 18 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mmo.html#fmt_mmo_o_ver
-
file rw---- s_and_t txt Microsoft Streets and Trips 2002-2007 xcsv
https://www.gpsbabel.org/WEB_DOC_DIR/fmt_s_and_t.html
option s_and_t snlen Max synthesized shortname length integer 1 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_s_and_t.html#fmt_s_and_t_o_snlen
option garmin_xt trk_header Track name processing option ([0]-nrm/1-ign) integer 0 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_garmin_xt.html#fmt_garmin_xt_o_trk_header
-file rw---- motoactv csv Motoactiv CSV xcsv
- https://www.gpsbabel.org/WEB_DOC_DIR/fmt_motoactv.html
-option motoactv snlen Max synthesized shortname length integer 1 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_motoactv.html#fmt_motoactv_o_snlen
-
-option motoactv snwhite Allow whitespace synth. shortnames boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_motoactv.html#fmt_motoactv_o_snwhite
-
-option motoactv snupper UPPERCASE synth. shortnames boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_motoactv.html#fmt_motoactv_o_snupper
-
-option motoactv snunique Make synth. shortnames unique boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_motoactv.html#fmt_motoactv_o_snunique
-
-option motoactv urlbase Basename prepended to URL on output string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_motoactv.html#fmt_motoactv_o_urlbase
-
-option motoactv prefer_shortnames Use shortname instead of description boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_motoactv.html#fmt_motoactv_o_prefer_shortnames
-
-option motoactv datum GPS datum (def. WGS 84) string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_motoactv.html#fmt_motoactv_o_datum
-
-file ----rw bcr bcr Motorrad Routenplaner (Map&Guide) .bcr files bcr
- https://www.gpsbabel.org/WEB_DOC_DIR/fmt_bcr.html
-option bcr index Index of route to write (if more than one in source) integer 1 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_bcr.html#fmt_bcr_o_index
-
-option bcr name New name for the route string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_bcr.html#fmt_bcr_o_name
-
-option bcr radius Radius of our big earth (default 6371000 meters) float 6371000 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_bcr.html#fmt_bcr_o_radius
-
-option bcr prefer_shortnames Use shortname instead of description boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_bcr.html#fmt_bcr_o_prefer_shortnames
-
file r-r--- mtk-bin bin MTK Logger (iBlue 747,...) Binary File Format mtk-bin
https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mtk-bin.html
option mtk-bin csv MTK compatible CSV output file string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mtk-bin.html#fmt_mtk-bin_o_csv
option mtk block_size_kb Size of blocks in KB to request from device integer 1 1 64 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mtk.html#fmt_mtk_o_block_size_kb
-file --r--- mynav trc MyNav TRC format mynav
- https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mynav.html
file rw---- tpg tpg National Geographic Topo .tpg (waypoints) tpg
https://www.gpsbabel.org/WEB_DOC_DIR/fmt_tpg.html
option tpg datum Datum (default=NAD27) string N. America 1927 mean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_tpg.html#fmt_tpg_o_datum
option nmea ignore_fix Accept position fixes in gpgga marked invalid boolean 0 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_nmea.html#fmt_nmea_o_ignore_fix
-file rw---- lmx Nokia Landmark Exchange lmx
- https://www.gpsbabel.org/WEB_DOC_DIR/fmt_lmx.html
-option lmx binary Compact binary representation boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_lmx.html#fmt_lmx_o_binary
-
file rw-wrw osm osm OpenStreetMap data files osm
https://www.gpsbabel.org/WEB_DOC_DIR/fmt_osm.html
option osm tag Write additional way tag key/value pairs string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_osm.html#fmt_osm_o_tag
shape ESRI shapefile
name Source for name field in .dbf
url Source for URL field in .dbf
- f90g F90G Automobile DVR GPS log file
igc FAI/IGC Flight Recorder Data Format
timeadj (integer sec or 'auto') Barograph to GPS time diff
garmin_fit Flexible and Interoperable Data Transfer (FIT) Act
altunits Units for altitude (f)eet or (m)etres
humminbird_ht Humminbird tracks (.ht)
humminbird Humminbird waypoints and routes (.hwr)
- ignrando IGN Rando track files
- index Index of track to write (if more than one in sourc
- igoprimo_poi iGo Primo points of interest (.upoi)
- snlen Max synthesized shortname length
- snwhite (0/1) Allow whitespace synth. shortnames
- snupper (0/1) UPPERCASE synth. shortnames
- snunique (0/1) Make synth. shortnames unique
- urlbase Basename prepended to URL on output
- prefer_shortnames (0/1) Use shortname instead of description
- datum GPS datum (def. WGS 84)
- igo2008_poi iGO2008 points of interest (.upoi)
- snlen Max synthesized shortname length
- snwhite (0/1) Allow whitespace synth. shortnames
- snupper (0/1) UPPERCASE synth. shortnames
- snunique (0/1) Make synth. shortnames unique
- urlbase Basename prepended to URL on output
- prefer_shortnames (0/1) Use shortname instead of description
- datum GPS datum (def. WGS 84)
- igo8 IGO8 .trk
- tracknum Track identification number
- title Track title
- description Track description
- kompass_tk Kompass (DAV) Track (.tk)
- snlen Max synthesized shortname length
- snwhite (0/1) Allow whitespace synth. shortnames
- snupper (0/1) UPPERCASE synth. shortnames
- snunique (0/1) Make synth. shortnames unique
- urlbase Basename prepended to URL on output
- prefer_shortnames (0/1) Use shortname instead of description
- datum GPS datum (def. WGS 84)
- kompass_wp Kompass (DAV) Waypoints (.wp)
- snlen Max synthesized shortname length
- snwhite (0/1) Allow whitespace synth. shortnames
- snupper (0/1) UPPERCASE synth. shortnames
- snunique (0/1) Make synth. shortnames unique
- urlbase Basename prepended to URL on output
- prefer_shortnames (0/1) Use shortname instead of description
- datum GPS datum (def. WGS 84)
lowranceusr Lowrance USR
ignoreicons (0/1) (USR input) Ignore event marker icons on read
writeasicons (0/1) (USR output) Treat waypoints as icons on write
baud Numeric value of bitrate (baud=4800)
noack (0/1) Suppress use of handshaking in name of speed
nukewpt (0/1) Delete all waypoints
- ik3d MagicMaps IK3D project file (.ikt)
- mainnav Mainnav
- snlen Max synthesized shortname length
- snwhite (0/1) Allow whitespace synth. shortnames
- snupper (0/1) UPPERCASE synth. shortnames
- snunique (0/1) Make synth. shortnames unique
- urlbase Basename prepended to URL on output
- prefer_shortnames (0/1) Use shortname instead of description
- datum GPS datum (def. WGS 84)
- tef Map&Guide 'TourExchangeFormat' XML
- routevia (0/1) Include only via stations in route
- mapasia_tr7 MapAsia track file (.tr7)
- mapbar Mapbar (China) navigation track for Sonim Xp3300
- mapfactor Mapfactor Navigator
- mapconverter Mapopolis.com Mapconverter CSV
- snlen Max synthesized shortname length
- snwhite (0/1) Allow whitespace synth. shortnames
- snupper (0/1) UPPERCASE synth. shortnames
- snunique (0/1) Make synth. shortnames unique
- urlbase Basename prepended to URL on output
- prefer_shortnames (0/1) Use shortname instead of description
- datum GPS datum (def. WGS 84)
- mxf MapTech Exchange Format
- snlen Max synthesized shortname length
- snwhite (0/1) Allow whitespace synth. shortnames
- snupper (0/1) UPPERCASE synth. shortnames
- snunique (0/1) Make synth. shortnames unique
- urlbase Basename prepended to URL on output
- prefer_shortnames (0/1) Use shortname instead of description
- datum GPS datum (def. WGS 84)
- mtk_locus MediaTek Locus
- baudrate Speed in bits per second of serial port (autodetec
- download (0/1) Download logged fixes
- erase (0/1) Erase device data after download
- status (0/1) Show device status
- enable (0/1) Enable logging after download
- mmo Memory-Map Navigator overlay files (.mmo)
- locked (0/1) Write items 'locked' [default no]
- visible (0/1) Write items 'visible' [default yes]
- ver Write files with internal version [n]
s_and_t Microsoft Streets and Trips 2002-2007
snlen Max synthesized shortname length
snwhite (0/1) Allow whitespace synth. shortnames
garmin_xt Mobile Garmin XT Track files
ftype Garmin Mobile XT ([ATRK]/STRK) (required)
trk_header Track name processing option ([0]-nrm/1-ign)
- motoactv Motoactiv CSV
- snlen Max synthesized shortname length
- snwhite (0/1) Allow whitespace synth. shortnames
- snupper (0/1) UPPERCASE synth. shortnames
- snunique (0/1) Make synth. shortnames unique
- urlbase Basename prepended to URL on output
- prefer_shortnames (0/1) Use shortname instead of description
- datum GPS datum (def. WGS 84)
- bcr Motorrad Routenplaner (Map&Guide) .bcr files
- index Index of route to write (if more than one in sourc
- name New name for the route
- radius Radius of our big earth (default 6371000 meters)
- prefer_shortnames (0/1) Use shortname instead of description
mtk-bin MTK Logger (iBlue 747,...) Binary File Format
csv MTK compatible CSV output file
mtk MTK Logger (iBlue 747,Qstarz BT-1000,...) download
log_enable (0/1) Enable logging after download
csv MTK compatible CSV output file
block_size_kb Size of blocks in KB to request from device
- mynav MyNav TRC format
tpg National Geographic Topo .tpg (waypoints)
datum Datum (default=NAD27)
tpo2 National Geographic Topo 2.x .tpo
baud Speed in bits per second of serial port (baud=4800
gisteq (0/1) Write tracks for Gisteq Phototracker
ignore_fix (0/1) Accept position fixes in gpgga marked invalid
- lmx Nokia Landmark Exchange
- binary (0/1) Compact binary representation
osm OpenStreetMap data files
tag Write additional way tag key/value pairs
tagnd Write additional node tag key/value pairs
+++ /dev/null
-No,Latitude,Longitude,Name,Description,Address,City,PostalCode,Phone\r
-1,50.877341,12.433889,"3","! constructed waypoint !","Hauptstrasse -1",,,"03741-999999"\r
-2,50.964955,12.435919,"Altenburg-Umgehung","! constructed waypoint !",,"Plauen",,"03741-999999"\r
-3,50.610795,12.173802,"Elsterberg","! constructed waypoint !",,,,"03741-999999"\r
-4,50.844126,12.408757,"Gosel","! constructed waypoint !",,,,"03741-999999"\r
-5,50.654763,12.204957,"Greiz","! constructed waypoint !",,,"08523","03741-999999"\r
-6,51.314521,12.409143,"HMMMM","No comment","Hauptstrasse -2","Plauen","08523","03741-999999"\r
-7,50.493663,12.107153,"Jahnstrasse","! constructed waypoint !",,,"08523","03741-999999"\r
-8,50.493837,12.106101,"Liebknechtstrasse","! constructed waypoint !",,,"08523","03741-999999"\r
-9,50.492619,12.105449,"NARVA","Start",,,"08523","03741-999999"\r
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<gpx version="1.0" creator="GPSBabel - https://www.gpsbabel.org" xmlns="http://www.topografix.com/GPX/1/0">
- <time>1970-01-01T00:00:00Z</time>
- <bounds minlat="50.492619000" minlon="12.105449000" maxlat="51.314521000" maxlon="12.435919000"/>
- <wpt lat="50.877341000" lon="12.433889000">
- <name>3</name>
- <cmt>! constructed waypoint !</cmt>
- <desc>! constructed waypoint !</desc>
- </wpt>
- <wpt lat="50.964955000" lon="12.435919000">
- <name>Altenburg-Umgehung</name>
- <cmt>! constructed waypoint !</cmt>
- <desc>! constructed waypoint !</desc>
- </wpt>
- <wpt lat="50.610795000" lon="12.173802000">
- <name>Elsterberg</name>
- <cmt>! constructed waypoint !</cmt>
- <desc>! constructed waypoint !</desc>
- </wpt>
- <wpt lat="50.844126000" lon="12.408757000">
- <name>Gosel</name>
- <cmt>! constructed waypoint !</cmt>
- <desc>! constructed waypoint !</desc>
- </wpt>
- <wpt lat="50.654763000" lon="12.204957000">
- <name>Greiz</name>
- <cmt>! constructed waypoint !</cmt>
- <desc>! constructed waypoint !</desc>
- </wpt>
- <wpt lat="51.314521000" lon="12.409143000">
- <name>HMMMM</name>
- <cmt>No comment</cmt>
- <desc>No comment</desc>
- </wpt>
- <wpt lat="50.493663000" lon="12.107153000">
- <name>Jahnstrasse</name>
- <cmt>! constructed waypoint !</cmt>
- <desc>! constructed waypoint !</desc>
- </wpt>
- <wpt lat="50.493837000" lon="12.106101000">
- <name>Liebknechtstrasse</name>
- <cmt>! constructed waypoint !</cmt>
- <desc>! constructed waypoint !</desc>
- </wpt>
- <wpt lat="50.492619000" lon="12.105449000">
- <name>NARVA</name>
- <cmt>Start</cmt>
- <desc>Start</desc>
- </wpt>
-</gpx>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<gpx version="1.0" creator="GPSBabel - https://www.gpsbabel.org" xmlns="http://www.topografix.com/GPX/1/0">
- <time>1970-01-01T00:00:00Z</time>
- <bounds minlat="38.857596000" minlon="-77.447755000" maxlat="38.952749000" maxlon="-77.008025000"/>
- <wpt lat="38.870741000" lon="-77.103000000">
- <name>Cathedral of St Thomas More</name>
- <cmt>Cathedral of St Thomas More</cmt>
- <desc>Cathedral of St Thomas More</desc>
- </wpt>
- <wpt lat="38.889742000" lon="-77.013587000">
- <name>Capitol Reflecting Pool</name>
- <cmt>Capitol Reflecting Pool</cmt>
- <desc>Capitol Reflecting Pool</desc>
- </wpt>
- <wpt lat="38.884787000" lon="-77.439315000">
- <name>McDonald's</name>
- <cmt>McDonald's</cmt>
- <desc>McDonald's</desc>
- </wpt>
- <wpt lat="38.952749000" lon="-77.447755000">
- <name>Washington Dulles International Airport</name>
- <cmt>Washington Dulles International Airport</cmt>
- <desc>Washington Dulles International Airport</desc>
- </wpt>
- <wpt lat="38.857596000" lon="-77.226819000">
- <name>Inova Fairfax Medical Campus</name>
- <cmt>Inova Fairfax Medical Campus</cmt>
- <desc>Inova Fairfax Medical Campus</desc>
- </wpt>
- <wpt lat="38.871771000" lon="-77.008025000">
- <name>Nationals Park</name>
- <cmt>Nationals Park</cmt>
- <desc>Nationals Park</desc>
- </wpt>
-</gpx>
+++ /dev/null
-No,Latitude,Longitude,Name,Address,City,PostalCode,Phone
-1,38.870741,-77.103000,"Cathedral of St Thomas More","Cathedral Ln","Arlington","22203","+(1)-(703)-5251300"
-2,38.889742,-77.013587,"Capitol Reflecting Pool",,"District of Columbia",,
-3,38.884787,-77.439315,"McDonald's","Brookfield Corporate Dr","Chantilly","20151",
-4,38.952749,-77.447755,"Washington Dulles International Airport","Saarinen Cir","Sterling","20166","+(1)-(703)-5722700"
-5,38.857596,-77.226819,"Inova Fairfax Medical Campus","Gallows Rd","Fairfax","22031","+(1)-(703)-7764001"
-6,38.871771,-77.008025,"Nationals Park","S Capitol St SE","Washington","20003","+(1)-(888)-6326287"
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<gpx version="1.0" creator="GPSBabel - https://www.gpsbabel.org" xmlns="http://www.topografix.com/GPX/1/0">
- <time>1970-01-01T00:00:00Z</time>
- <bounds minlat="50.492606163" minlon="12.105131149" maxlat="51.314635752" maxlon="12.414971469"/>
- <wpt lat="50.493662870" lon="12.107152529">
- <name>Jahnstrasse</name>
- <cmt>Jahnstrasse 11</cmt>
- <desc>Jahnstrasse 11</desc>
- </wpt>
- <wpt lat="50.493837046" lon="12.106101019">
- <name>Liebknechtstrasse</name>
- <cmt>Liebknechtstrasse 90</cmt>
- <desc>Liebknechtstrasse 90</desc>
- </wpt>
- <wpt lat="50.492618987" lon="12.105448823">
- <name>NARVA</name>
- <cmt>Start</cmt>
- <desc>Start</desc>
- </wpt>
- <trk>
- <name>NARVA to Jahnstrasse</name>
- <trkseg>
- <trkpt lat="50.492618987" lon="12.105448823"/>
- <trkpt lat="50.492606163" lon="12.105431557"/>
- <trkpt lat="50.492606163" lon="12.105431557"/>
- <trkpt lat="50.494279861" lon="12.105131149"/>
- <trkpt lat="50.493836962" lon="12.106101271"/>
- <trkpt lat="50.493837046" lon="12.106101019"/>
- <trkpt lat="50.493836962" lon="12.106101271"/>
- <trkpt lat="50.493378639" lon="12.107105255"/>
- <trkpt lat="50.493662786" lon="12.107152529"/>
- <trkpt lat="50.493662870" lon="12.107152529"/>
- </trkseg>
- </trk>
- <trk>
- <name>ACTIVE LOG 006</name>
- <trkseg>
- <trkpt lat="51.312941350" lon="12.413165923"/>
- <trkpt lat="51.312885778" lon="12.413249239"/>
- <trkpt lat="51.312858034" lon="12.413249239"/>
- <trkpt lat="51.312830206" lon="12.413304811"/>
- <trkpt lat="51.312830206" lon="12.413276983"/>
- <trkpt lat="51.312830206" lon="12.413304811"/>
- <trkpt lat="51.312774718" lon="12.413332555"/>
- <trkpt lat="51.312774718" lon="12.413332555"/>
- <trkpt lat="51.312746890" lon="12.413332555"/>
- <trkpt lat="51.312802462" lon="12.413304811"/>
- <trkpt lat="51.312913606" lon="12.413443699"/>
- <trkpt lat="51.312996922" lon="12.413804792"/>
- <trkpt lat="51.313052494" lon="12.413804792"/>
- <trkpt lat="51.313052494" lon="12.413832536"/>
- <trkpt lat="51.313107982" lon="12.413832536"/>
- <trkpt lat="51.313219126" lon="12.413888108"/>
- <trkpt lat="51.313302442" lon="12.413971424"/>
- <trkpt lat="51.313274698" lon="12.414054740"/>
- <trkpt lat="51.313274698" lon="12.414110312"/>
- <trkpt lat="51.313052494" lon="12.414610293"/>
- <trkpt lat="51.312969094" lon="12.414832581"/>
- <trkpt lat="51.312913606" lon="12.414943641"/>
- <trkpt lat="51.312941350" lon="12.414971469"/>
- <trkpt lat="51.312941350" lon="12.414971469"/>
- <trkpt lat="51.312969094" lon="12.414943641"/>
- <trkpt lat="51.313163554" lon="12.414582549"/>
- <trkpt lat="51.313163554" lon="12.414554805"/>
- <trkpt lat="51.313163554" lon="12.414443661"/>
- <trkpt lat="51.313163554" lon="12.414388089"/>
- <trkpt lat="51.313330270" lon="12.413915852"/>
- <trkpt lat="51.313691363" lon="12.413332555"/>
- <trkpt lat="51.313996883" lon="12.412860319"/>
- <trkpt lat="51.314219087" lon="12.412499227"/>
- <trkpt lat="51.314635752" lon="12.409554748"/>
- <trkpt lat="51.314635752" lon="12.409499260"/>
- <trkpt lat="51.314635752" lon="12.409499260"/>
- <trkpt lat="51.314635752" lon="12.409443688"/>
- <trkpt lat="51.314635752" lon="12.409360288"/>
- <trkpt lat="51.314635752" lon="12.409360288"/>
- <trkpt lat="51.314635752" lon="12.409360288"/>
- <trkpt lat="51.314635752" lon="12.409360288"/>
- <trkpt lat="51.314635752" lon="12.409360288"/>
- </trkseg>
- </trk>
-</gpx>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8" ?>
-<Root FileFormat="IK3D-Project-File" >
- <Info>
- <ProductVersion>
- <Version>Germany TK25 Demo</Version>
- <FileFormatVersion>1.1</FileFormatVersion>
- </ProductVersion>
- <Language>German</Language>
- </Info>
- <Header>
- <Projectname>Undefiniert</Projectname>
- <countOfObjects>5</countOfObjects>
- <description><![CDATA[keine Beschreibung vorhanden]]></description>
- </Header>
- <Content>
- <MMGeoObjects>
- <count>5</count>
- <MMGeoObject_0>
- <GeoObjectType>0</GeoObjectType>
- <Name>Jahnstrasse</Name>
- <Remark></Remark>
- <Link></Link>
- <Priority>0</Priority>
- <ID>132048172029964614</ID>
- <Locked>False</Locked>
- <GeoPosition X="12.1071525290" Y="50.4936628700" />
- <DrawType2D>1</DrawType2D>
- <DrawType3D>1</DrawType3D>
- <POIDrawable2D>
- <Text>Jahnstrasse 11</Text>
- <BorderColor Blue="0.0000" Red="0.0000" Green="0.0000" />
- <TextColor Blue="0.0000" Red="0.0000" Green="0.0000" />
- <BorderType>2</BorderType>
- <BackRounded>True</BackRounded>
- <Distance>32.0000000000</Distance>
- <BackAlpha>1.0000000000</BackAlpha>
- <ArrowColor Blue="1.0000" Red="1.0000" Green="1.0000" />
- <FrameColor Blue="0.2000" Red="0.8980" Green="0.8980" />
- <Height>16.0000000000</Height>
- <Frame>1</Frame>
- <PicFileName>.\default.jpg</PicFileName>
- <MarkerType>0</MarkerType>
- <antiAliasing>False</antiAliasing>
- <TextDesc>0.0000000000</TextDesc>
- <Orientation>1</Orientation>
- <ScaleFac>1.0000000000</ScaleFac>
- </POIDrawable2D>
- <POIDrawable3D>
- <Text>Jahnstrasse 11</Text>
- <BorderColor Blue="0.0000" Red="0.0000" Green="0.0000" />
- <TextColor Blue="0.0000" Red="0.0000" Green="0.0000" />
- <BorderType>2</BorderType>
- <BackRounded>False</BackRounded>
- <Distance>99.0000000000</Distance>
- <BackAlpha>1.0000000000</BackAlpha>
- <ArrowColor Blue="0.6000" Red="0.6000" Green="0.6000" />
- <FrameColor Blue="0.2000" Red="0.8980" Green="0.8980" />
- <Height>180.0000000000</Height>
- <Frame>1</Frame>
- <PicFileName>.\default.jpg</PicFileName>
- <antiAliasing>False</antiAliasing>
- <TextDesc>-36.0000000000</TextDesc>
- <Orientation>1</Orientation>
- <ScaleFac>0.2500000000</ScaleFac>
- </POIDrawable3D>
- </MMGeoObject_0>
- <MMGeoObject_1>
- <GeoObjectType>0</GeoObjectType>
- <Name>Liebknechtstrasse</Name>
- <Remark></Remark>
- <Link></Link>
- <Priority>1</Priority>
- <ID>194043035650486614</ID>
- <Locked>False</Locked>
- <GeoPosition X="12.1061010190" Y="50.4938370460" />
- <DrawType2D>1</DrawType2D>
- <DrawType3D>1</DrawType3D>
- <POIDrawable2D>
- <Text>Liebknechtstrasse 90</Text>
- <BorderColor Blue="0.0000" Red="0.0000" Green="0.0000" />
- <TextColor Blue="0.0000" Red="0.0000" Green="0.0000" />
- <BorderType>2</BorderType>
- <BackRounded>True</BackRounded>
- <Distance>32.0000000000</Distance>
- <BackAlpha>1.0000000000</BackAlpha>
- <ArrowColor Blue="1.0000" Red="1.0000" Green="1.0000" />
- <FrameColor Blue="0.2000" Red="0.8980" Green="0.8980" />
- <Height>16.0000000000</Height>
- <Frame>1</Frame>
- <PicFileName>.\default.jpg</PicFileName>
- <MarkerType>0</MarkerType>
- <antiAliasing>False</antiAliasing>
- <TextDesc>0.0000000000</TextDesc>
- <Orientation>1</Orientation>
- <ScaleFac>1.0000000000</ScaleFac>
- </POIDrawable2D>
- <POIDrawable3D>
- <Text>Liebknechtstrasse 90</Text>
- <BorderColor Blue="0.0000" Red="0.0000" Green="0.0000" />
- <TextColor Blue="0.0000" Red="0.0000" Green="0.0000" />
- <BorderType>2</BorderType>
- <BackRounded>False</BackRounded>
- <Distance>100.0000000000</Distance>
- <BackAlpha>1.0000000000</BackAlpha>
- <ArrowColor Blue="0.6000" Red="0.6000" Green="0.6000" />
- <FrameColor Blue="0.2000" Red="0.8980" Green="0.8980" />
- <Height>180.0000000000</Height>
- <Frame>1</Frame>
- <PicFileName>.\default.jpg</PicFileName>
- <antiAliasing>False</antiAliasing>
- <TextDesc>-36.0000000000</TextDesc>
- <Orientation>1</Orientation>
- <ScaleFac>0.2500000000</ScaleFac>
- </POIDrawable3D>
- </MMGeoObject_1>
- <MMGeoObject_2>
- <GeoObjectType>0</GeoObjectType>
- <Name>NARVA</Name>
- <Remark></Remark>
- <Link></Link>
- <Priority>2</Priority>
- <ID>319457729961128278</ID>
- <Locked>False</Locked>
- <GeoPosition X="12.1054488230" Y="50.4926189870" />
- <DrawType2D>1</DrawType2D>
- <DrawType3D>1</DrawType3D>
- <POIDrawable2D>
- <Text>Start</Text>
- <BorderColor Blue="0.0000" Red="0.0000" Green="0.0000" />
- <TextColor Blue="0.0000" Red="0.0000" Green="0.0000" />
- <BorderType>2</BorderType>
- <BackRounded>True</BackRounded>
- <Distance>32.0000000000</Distance>
- <BackAlpha>1.0000000000</BackAlpha>
- <ArrowColor Blue="1.0000" Red="1.0000" Green="1.0000" />
- <FrameColor Blue="0.2000" Red="0.8980" Green="0.8980" />
- <Height>16.0000000000</Height>
- <Frame>1</Frame>
- <PicFileName>.\default.jpg</PicFileName>
- <MarkerType>0</MarkerType>
- <antiAliasing>False</antiAliasing>
- <TextDesc>0.0000000000</TextDesc>
- <Orientation>1</Orientation>
- <ScaleFac>1.0000000000</ScaleFac>
- </POIDrawable2D>
- <POIDrawable3D>
- <Text>Start</Text>
- <BorderColor Blue="0.0000" Red="0.0000" Green="0.0000" />
- <TextColor Blue="0.0000" Red="0.0000" Green="0.0000" />
- <BorderType>2</BorderType>
- <BackRounded>False</BackRounded>
- <Distance>99.0000000000</Distance>
- <BackAlpha>1.0000000000</BackAlpha>
- <ArrowColor Blue="0.6000" Red="0.6000" Green="0.6000" />
- <FrameColor Blue="0.2000" Red="0.8980" Green="0.8980" />
- <Height>180.0000000000</Height>
- <Frame>1</Frame>
- <PicFileName>.\default.jpg</PicFileName>
- <antiAliasing>False</antiAliasing>
- <TextDesc>-36.0000000000</TextDesc>
- <Orientation>1</Orientation>
- <ScaleFac>0.2500000000</ScaleFac>
- </POIDrawable3D>
- </MMGeoObject_2>
- <MMGeoObject_3>
- <GeoObjectType>1</GeoObjectType>
- <Name>NARVA to Jahnstrasse</Name>
- <Remark></Remark>
- <Link></Link>
- <Priority>3</Priority>
- <ID>232341224669180246</ID>
- <Locked>False</Locked>
- <PathWidthFactor>1.0000000000</PathWidthFactor>
- <PathDrawType>5</PathDrawType>
- <PathPoints>
- <count>10</count>
- <Point_0>
- <Link></Link>
- <GeoPosition X="12.1054488230" Y="50.4926189870" />
- </Point_0>
- <Point_1>
- <Link></Link>
- <GeoPosition X="12.1054315570" Y="50.4926061630" />
- </Point_1>
- <Point_2>
- <Link></Link>
- <GeoPosition X="12.1054315570" Y="50.4926061630" />
- </Point_2>
- <Point_3>
- <Link></Link>
- <GeoPosition X="12.1051311490" Y="50.4942798610" />
- </Point_3>
- <Point_4>
- <Link></Link>
- <GeoPosition X="12.1061012710" Y="50.4938369620" />
- </Point_4>
- <Point_5>
- <Link></Link>
- <GeoPosition X="12.1061010190" Y="50.4938370460" />
- </Point_5>
- <Point_6>
- <Link></Link>
- <GeoPosition X="12.1061012710" Y="50.4938369620" />
- </Point_6>
- <Point_7>
- <Link></Link>
- <GeoPosition X="12.1071052550" Y="50.4933786390" />
- </Point_7>
- <Point_8>
- <Link></Link>
- <GeoPosition X="12.1071525290" Y="50.4936627860" />
- </Point_8>
- <Point_9>
- <Link></Link>
- <GeoPosition X="12.1071525290" Y="50.4936628700" />
- </Point_9>
- </PathPoints>
- <PathDrawable2D>
- <PathColor Blue="0.0000" Red="1.0000" Green="0.0000" />
- <PointColor Blue="0.0000" Red="1.0000" Green="1.0000" />
- <MarkingColor Blue="1.0000" Red="1.0000" Green="0.0000" />
- <Alpha>1.0000000000</Alpha>
- <Antialiasing>False</Antialiasing>
- <CirclePieces>12</CirclePieces>
- </PathDrawable2D>
- <PathDrawable3D>
- <PathColor Blue="0.0000" Red="1.0000" Green="0.0000" />
- <PointColor Blue="0.0000" Red="1.0000" Green="1.0000" />
- <MarkingColor Blue="1.0000" Red="1.0000" Green="0.0000" />
- <Alpha>1.0000000000</Alpha>
- <Antialiasing>False</Antialiasing>
- </PathDrawable3D>
- </MMGeoObject_3>
- <MMGeoObject_4>
- <GeoObjectType>1</GeoObjectType>
- <Name>ACTIVE LOG 006</Name>
- <Remark></Remark>
- <Link></Link>
- <Priority>4</Priority>
- <ID>387926518045995350</ID>
- <Locked>False</Locked>
- <PathWidthFactor>1.0000000000</PathWidthFactor>
- <PathDrawType>5</PathDrawType>
- <PathPoints>
- <count>42</count>
- <Point_0>
- <Link></Link>
- <GeoPosition X="12.4131659230" Y="51.3129413500" />
- </Point_0>
- <Point_1>
- <Link></Link>
- <GeoPosition X="12.4132492390" Y="51.3128857780" />
- </Point_1>
- <Point_2>
- <Link></Link>
- <GeoPosition X="12.4132492390" Y="51.3128580340" />
- </Point_2>
- <Point_3>
- <Link></Link>
- <GeoPosition X="12.4133048110" Y="51.3128302060" />
- </Point_3>
- <Point_4>
- <Link></Link>
- <GeoPosition X="12.4132769830" Y="51.3128302060" />
- </Point_4>
- <Point_5>
- <Link></Link>
- <GeoPosition X="12.4133048110" Y="51.3128302060" />
- </Point_5>
- <Point_6>
- <Link></Link>
- <GeoPosition X="12.4133325550" Y="51.3127747180" />
- </Point_6>
- <Point_7>
- <Link></Link>
- <GeoPosition X="12.4133325550" Y="51.3127747180" />
- </Point_7>
- <Point_8>
- <Link></Link>
- <GeoPosition X="12.4133325550" Y="51.3127468900" />
- </Point_8>
- <Point_9>
- <Link></Link>
- <GeoPosition X="12.4133048110" Y="51.3128024620" />
- </Point_9>
- <Point_10>
- <Link></Link>
- <GeoPosition X="12.4134436990" Y="51.3129136060" />
- </Point_10>
- <Point_11>
- <Link></Link>
- <GeoPosition X="12.4138047920" Y="51.3129969220" />
- </Point_11>
- <Point_12>
- <Link></Link>
- <GeoPosition X="12.4138047920" Y="51.3130524940" />
- </Point_12>
- <Point_13>
- <Link></Link>
- <GeoPosition X="12.4138325360" Y="51.3130524940" />
- </Point_13>
- <Point_14>
- <Link></Link>
- <GeoPosition X="12.4138325360" Y="51.3131079820" />
- </Point_14>
- <Point_15>
- <Link></Link>
- <GeoPosition X="12.4138881080" Y="51.3132191260" />
- </Point_15>
- <Point_16>
- <Link></Link>
- <GeoPosition X="12.4139714240" Y="51.3133024420" />
- </Point_16>
- <Point_17>
- <Link></Link>
- <GeoPosition X="12.4140547400" Y="51.3132746980" />
- </Point_17>
- <Point_18>
- <Link></Link>
- <GeoPosition X="12.4141103120" Y="51.3132746980" />
- </Point_18>
- <Point_19>
- <Link></Link>
- <GeoPosition X="12.4146102930" Y="51.3130524940" />
- </Point_19>
- <Point_20>
- <Link></Link>
- <GeoPosition X="12.4148325810" Y="51.3129690940" />
- </Point_20>
- <Point_21>
- <Link></Link>
- <GeoPosition X="12.4149436410" Y="51.3129136060" />
- </Point_21>
- <Point_22>
- <Link></Link>
- <GeoPosition X="12.4149714690" Y="51.3129413500" />
- </Point_22>
- <Point_23>
- <Link></Link>
- <GeoPosition X="12.4149714690" Y="51.3129413500" />
- </Point_23>
- <Point_24>
- <Link></Link>
- <GeoPosition X="12.4149436410" Y="51.3129690940" />
- </Point_24>
- <Point_25>
- <Link></Link>
- <GeoPosition X="12.4145825490" Y="51.3131635540" />
- </Point_25>
- <Point_26>
- <Link></Link>
- <GeoPosition X="12.4145548050" Y="51.3131635540" />
- </Point_26>
- <Point_27>
- <Link></Link>
- <GeoPosition X="12.4144436610" Y="51.3131635540" />
- </Point_27>
- <Point_28>
- <Link></Link>
- <GeoPosition X="12.4143880890" Y="51.3131635540" />
- </Point_28>
- <Point_29>
- <Link></Link>
- <GeoPosition X="12.4139158520" Y="51.3133302700" />
- </Point_29>
- <Point_30>
- <Link></Link>
- <GeoPosition X="12.4133325550" Y="51.3136913630" />
- </Point_30>
- <Point_31>
- <Link></Link>
- <GeoPosition X="12.4128603190" Y="51.3139968830" />
- </Point_31>
- <Point_32>
- <Link></Link>
- <GeoPosition X="12.4124992270" Y="51.3142190870" />
- </Point_32>
- <Point_33>
- <Link></Link>
- <GeoPosition X="12.4095547480" Y="51.3146357520" />
- </Point_33>
- <Point_34>
- <Link></Link>
- <GeoPosition X="12.4094992600" Y="51.3146357520" />
- </Point_34>
- <Point_35>
- <Link></Link>
- <GeoPosition X="12.4094992600" Y="51.3146357520" />
- </Point_35>
- <Point_36>
- <Link></Link>
- <GeoPosition X="12.4094436880" Y="51.3146357520" />
- </Point_36>
- <Point_37>
- <Link></Link>
- <GeoPosition X="12.4093602880" Y="51.3146357520" />
- </Point_37>
- <Point_38>
- <Link></Link>
- <GeoPosition X="12.4093602880" Y="51.3146357520" />
- </Point_38>
- <Point_39>
- <Link></Link>
- <GeoPosition X="12.4093602880" Y="51.3146357520" />
- </Point_39>
- <Point_40>
- <Link></Link>
- <GeoPosition X="12.4093602880" Y="51.3146357520" />
- </Point_40>
- <Point_41>
- <Link></Link>
- <GeoPosition X="12.4093602880" Y="51.3146357520" />
- </Point_41>
- </PathPoints>
- <PathDrawable2D>
- <PathColor Blue="0.0000" Red="1.0000" Green="0.0000" />
- <PointColor Blue="0.0000" Red="1.0000" Green="1.0000" />
- <MarkingColor Blue="1.0000" Red="1.0000" Green="0.0000" />
- <Alpha>1.0000000000</Alpha>
- <Antialiasing>False</Antialiasing>
- <CirclePieces>12</CirclePieces>
- </PathDrawable2D>
- <PathDrawable3D>
- <PathColor Blue="0.0000" Red="1.0000" Green="0.0000" />
- <PointColor Blue="0.0000" Red="1.0000" Green="1.0000" />
- <MarkingColor Blue="1.0000" Red="1.0000" Green="0.0000" />
- <Alpha>1.0000000000</Alpha>
- <Antialiasing>False</Antialiasing>
- </PathDrawable3D>
- </MMGeoObject_4>
- </MMGeoObjects>
- </Content>
-</Root>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<favourites version="1">
- <item name="Hoverdal F1 Sørup sande" lat="202224421" lon="30145835"/>
- <item name="Hoverdal F2 Hulmose" lat="202269707" lon="30104875"/>
- <item name="Hoverdal F2-1" lat="202255158" lon="30107287"/>
- <item name="Hoverdal F3 Oldtidsagre" lat="202274369" lon="30001910"/>
- <item name="Hoverdal I1" lat="202196320" lon="30474553"/>
- <item name="Hoverdal I2" lat="202253947" lon="30063905"/>
- <item name="Hoverdal I3" lat="202210534" lon="30245668"/>
- <item name="Hoverdal I4 Sø" lat="202243663" lon="30083458"/>
- <item name="Hoverdal P1" lat="202207154" lon="30294894"/>
-</favourites>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<gpx version="1.0" creator="GPSBabel - https://www.gpsbabel.org" xmlns="http://www.topografix.com/GPX/1/0">
- <time>1970-01-01T00:00:00Z</time>
- <bounds minlat="56.165644444" minlon="8.333863889" maxlat="56.187324722" maxlon="8.465153611"/>
- <wpt lat="56.173450278" lon="8.373843056">
- <name>Hoverdal F1 Sørup sande</name>
- <cmt>Hoverdal F1 Sørup sande</cmt>
- <desc>Hoverdal F1 Sørup sande</desc>
- </wpt>
- <wpt lat="56.186029722" lon="8.362465278">
- <name>Hoverdal F2 Hulmose</name>
- <cmt>Hoverdal F2 Hulmose</cmt>
- <desc>Hoverdal F2 Hulmose</desc>
- </wpt>
- <wpt lat="56.181988333" lon="8.363135278">
- <name>Hoverdal F2-1</name>
- <cmt>Hoverdal F2-1</cmt>
- <desc>Hoverdal F2-1</desc>
- </wpt>
- <wpt lat="56.187324722" lon="8.333863889">
- <name>Hoverdal F3 Oldtidsagre</name>
- <cmt>Hoverdal F3 Oldtidsagre</cmt>
- <desc>Hoverdal F3 Oldtidsagre</desc>
- </wpt>
- <wpt lat="56.165644444" lon="8.465153611">
- <name>Hoverdal I1</name>
- <cmt>Hoverdal I1</cmt>
- <desc>Hoverdal I1</desc>
- </wpt>
- <wpt lat="56.181651944" lon="8.351084722">
- <name>Hoverdal I2</name>
- <cmt>Hoverdal I2</cmt>
- <desc>Hoverdal I2</desc>
- </wpt>
- <wpt lat="56.169592778" lon="8.401574444">
- <name>Hoverdal I3</name>
- <cmt>Hoverdal I3</cmt>
- <desc>Hoverdal I3</desc>
- </wpt>
- <wpt lat="56.178795278" lon="8.356516111">
- <name>Hoverdal I4 Sø</name>
- <cmt>Hoverdal I4 Sø</cmt>
- <desc>Hoverdal I4 Sø</desc>
- </wpt>
- <wpt lat="56.168653889" lon="8.415248333">
- <name>Hoverdal P1</name>
- <cmt>Hoverdal P1</cmt>
- <desc>Hoverdal P1</desc>
- </wpt>
-</gpx>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<gpx version="1.0" creator="GPSBabel - https://www.gpsbabel.org" xmlns="http://www.topografix.com/GPX/1/0">
- <time>1970-01-01T00:00:00Z</time>
- <bounds minlat="51.061111450" minlon="-114.124198914" maxlat="51.061264038" maxlon="-114.123962402"/>
- <wpt lat="51.061149597" lon="-114.124061584">
- <ele>1117.000</ele>
- <time>2012-10-26T18:02:55Z</time>
- <name>WPT001</name>
- <cmt>WPT001</cmt>
- <desc>WPT001</desc>
- <fix>3d</fix>
- </wpt>
- <wpt lat="51.061218262" lon="-114.124145508">
- <ele>1116.000</ele>
- <time>2012-10-26T18:03:10Z</time>
- <name>WPT002</name>
- <cmt>WPT002</cmt>
- <desc>WPT002</desc>
- <fix>3d</fix>
- </wpt>
- <wpt lat="51.061264038" lon="-114.124198914">
- <ele>1115.000</ele>
- <time>2012-10-26T18:03:25Z</time>
- <name>WPT003</name>
- <cmt>WPT003</cmt>
- <desc>WPT003</desc>
- <fix>3d</fix>
- </wpt>
- <wpt lat="51.061252594" lon="-114.124168396">
- <ele>1115.000</ele>
- <time>2012-10-26T18:03:40Z</time>
- <name>WPT004</name>
- <cmt>WPT004</cmt>
- <desc>WPT004</desc>
- <fix>3d</fix>
- </wpt>
- <wpt lat="51.061264038" lon="-114.124176025">
- <ele>1114.000</ele>
- <time>2012-10-26T18:03:55Z</time>
- <name>WPT005</name>
- <cmt>WPT005</cmt>
- <desc>WPT005</desc>
- <fix>3d</fix>
- </wpt>
- <wpt lat="51.061244965" lon="-114.124145508">
- <ele>1112.000</ele>
- <time>2012-10-26T18:04:10Z</time>
- <name>WPT006</name>
- <cmt>WPT006</cmt>
- <desc>WPT006</desc>
- <fix>3d</fix>
- </wpt>
- <wpt lat="51.061195374" lon="-114.124084473">
- <ele>1111.000</ele>
- <time>2012-10-26T18:04:25Z</time>
- <name>WPT007</name>
- <cmt>WPT007</cmt>
- <desc>WPT007</desc>
- <fix>3d</fix>
- </wpt>
- <wpt lat="51.061149597" lon="-114.124053955">
- <ele>1108.000</ele>
- <time>2012-10-26T18:04:40Z</time>
- <name>WPT008</name>
- <cmt>WPT008</cmt>
- <desc>WPT008</desc>
- <fix>3d</fix>
- </wpt>
- <wpt lat="51.061126709" lon="-114.124053955">
- <ele>1106.000</ele>
- <time>2012-10-26T18:04:55Z</time>
- <name>WPT009</name>
- <cmt>WPT009</cmt>
- <desc>WPT009</desc>
- <fix>3d</fix>
- </wpt>
- <wpt lat="51.061122894" lon="-114.124061584">
- <ele>1106.000</ele>
- <time>2012-10-26T18:05:10Z</time>
- <name>WPT010</name>
- <cmt>WPT010</cmt>
- <desc>WPT010</desc>
- <fix>3d</fix>
- </wpt>
- <wpt lat="51.061126709" lon="-114.124122620">
- <ele>1104.000</ele>
- <time>2012-10-26T18:05:25Z</time>
- <name>WPT011</name>
- <cmt>WPT011</cmt>
- <desc>WPT011</desc>
- <fix>3d</fix>
- </wpt>
- <wpt lat="51.061111450" lon="-114.124114990">
- <ele>1103.000</ele>
- <time>2012-10-26T18:05:40Z</time>
- <name>WPT012</name>
- <cmt>WPT012</cmt>
- <desc>WPT012</desc>
- <fix>3d</fix>
- </wpt>
- <wpt lat="51.061126709" lon="-114.124069214">
- <ele>1101.000</ele>
- <time>2012-10-26T18:05:55Z</time>
- <name>WPT013</name>
- <cmt>WPT013</cmt>
- <desc>WPT013</desc>
- <fix>3d</fix>
- </wpt>
- <wpt lat="51.061199188" lon="-114.123962402">
- <ele>1097.000</ele>
- <time>2012-10-26T18:06:10Z</time>
- <name>WPT014</name>
- <cmt>WPT014</cmt>
- <desc>WPT014</desc>
- <fix>3d</fix>
- </wpt>
- <trk/>
-</gpx>
+++ /dev/null
-blah7.000,A,5103.6616,N,11407.4451,W,0.63,333.96,261012,,,A*7D
-$GPVTG,333.96,T,,M,0.63,N,1.17,K,A*33
-$PGTOP,11,2*6E
-$GPGGA,192518.000,5103.6617,N,11407.4452,W,1,8,1.10,1091.7,M,-17.5,M,,*55
-$GPGSA,A,3,05,10,29,02,25,04,12,31,,,,,2.08,1.10,1.76*07
-$GPRMC,192518.000,A,5103.6617,N,11407.4452,W,0.38,333.96,261012,,,A*7E
-$GPVTG,333.96,T,,M,0.38,N,0.71,K,A*3C
-$PMTKLOX,0,3*5A
-$PMTKLOX,1,0,0100010A,1F000000,0F000000,0000100A,00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000001F,FFFFFFFF,FFFFFFFF,FFFFFFFF,000C8C14,4FD08A50,029E3E4C,42853FE4,C25D042C,5ED08A50,02B03E4C,42903FE4,C25C0407*5B
-$PMTKLOX,1,1,6DD08A50,02BC3E4C,42973FE4,C25B0438,7CD08A50,02B93E4C,42933FE4,C25B0428,8BD08A50,02BC3E4C,42943FE4,C25A04DC,9AD08A50,02B73E4C,42903FE4,C25804C0,A9D08A50,02AA3E4C,42883FE4,C25704F9,B8D08A50,029E3E4C,42843FE4,C25404D3*26
-$PMTKLOX,1,2,C7D08A50,02983E4C,42843FE4,C25204AC,D6D08A50,02973E4C,42853FE4,C25204B3,E5D08A50,02983E4C,428D3FE4,C2500485,F4D08A50,02943E4C,428C3FE4,C24F0486,03D18A50,02983E4C,42863FE4,C24D0474,12D18A50,02AB3E4C,42783FE4,C24904AC*23
-$PMTKLOX,2*47
-$PGTOP,11,2*6E
-$GPGGA,192539.000,5103.6648,N,11407.4450,W,1,8,1.10,1092.1,M,-17.5,M,,*5B
-$GPGSA,A,3,05,10,29,02,25,04,12,31,,,,,2.08,1.10,1.77*06
-$GPGSV,3,1,11,02,75,084,31,12,63,194,21,25,58,284,26,10,41,083,21*70
+++ /dev/null
-35.97203, -87.13470, "Mountain Bike Heaven by susy1313", "GCEBB", "Mountain Bike Heaven by susy1313", ff0000, 47
-36.09068, -86.67955, "The Troll by a182pilot & Family", "GC1A37", "The Troll by a182pilot & Family", ff0000, 47
-35.99627, -86.62012, "Dive Bomber by JoGPS & family", "GC1C2B", "Dive Bomber by JoGPS & family", ff0000, 47
-36.03848, -86.64862, "FOSTER by JoGPS & Family", "GC25A9", "FOSTER by JoGPS & Family", ff0000, 47
-36.11218, -86.74177, "Logan Lighthouse by JoGps & Family", "GC2723", "Logan Lighthouse by JoGps & Family", ff0000, 47
-36.06408, -86.79052, "Ganier Cache by Susy1313", "GC2B71", "Ganier Cache by Susy1313", ff0000, 47
-36.08777, -86.80973, "Shy's Hill by FireFighterEng33", "GC309F", "Shy's Hill by FireFighterEng33", ff0000, 47
-36.05750, -86.89200, "GittyUp by JoGPS / Warner Parks", "GC317A", "GittyUp by JoGPS / Warner Parks", ff0000, 47
-36.08280, -86.86728, "Inlighting by JoGPS / Warner Parks", "GC317D", "Inlighting by JoGPS / Warner Parks", ff0000, 47
+++ /dev/null
-# gpsbabel XCSV style file
-#
-# Format: iGO2008 points of interest
-# Author: Olaf Klein
-# Date: 09/05/2008
-#
-DESCRIPTION iGO2008 points of interest (.upoi)
-EXTENSION upoi
-DATATYPE WAYPOINT
-#
-# FILE LAYOUT DEFINITIIONS:
-#
-FIELD_DELIMITER PIPE
-RECORD_DELIMITER CRNEWLINE
-BADCHARS "|
-ENCODING windows-1252
-#
-# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE:
-#
-IFIELD INDEX,"1","%d"
-IFIELD DESCRIPTION, "", "%s"
-IFIELD SHORTNAME, "", "%s"
-IFIELD IGNORE, "", "%s" # nothing
-IFIELD LAT_DECIMAL, "", "%.6f"
-IFIELD LON_DECIMAL, "", "%.6f"
-IFIELD IGNORE, "", "%s" # Name of map
-IFIELD IGNORE, "", "%s" # nothing
-IFIELD POSTAL_CODE, "", "%s"
-IFIELD CITY, "", "%s"
-IFIELD STREET_ADDR, "", "%s" # Street without number
-IFIELD IGNORE, "", "%s" # Street number
-IFIELD NOTES, "", "%s"
-IFIELD PHONE_NR, "", "%s"
+++ /dev/null
-# gpsbabel XCSV style file
-#
-# Format: iGo Primo points of interest
-# Author: Scott Bradford
-# Date: 03/26/2016
-#
-DESCRIPTION iGo Primo points of interest (.upoi)
-EXTENSION upoi
-DATATYPE WAYPOINT
-#
-# FILE LAYOUT DEFINITIONS:
-#
-FIELD_DELIMITER PIPE
-RECORD_DELIMITER NEWLINE
-BADCHARS "|
-ENCODING UTF-16LE
-#
-# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE:
-#
-IFIELD INDEX, "1", "%d"
-IFIELD CONSTANT, "@Favourites", "%s" # always @Favourites?
-IFIELD SHORTNAME, "", "%s"
-IFIELD IGNORE, "", "%s" # always empty?
-IFIELD LAT_DECIMAL, "", "%.6f"
-IFIELD LON_DECIMAL, "", "%.6f"
-IFIELD CONSTANT, "_u**", "%s" # always _u**?
-IFIELD IGNORE, "", "%s" # always empty?
-IFIELD CONSTANT, "_uva", "%s" # always _uva?
-IFIELD IGNORE, "", "%s" # always empty?
-IFIELD POSTAL_CODE, "", "%s"
-IFIELD CITY, "", "%s"
-IFIELD STREET_ADDR, "", "%s" # should be street name (no number)
-IFIELD IGNORE, "", "%s" # should be street number
-IFIELD IGNORE, "", "%s" # always empty?
-IFIELD PHONE_NR, "", "%s"
-IFIELD IGNORE, "", "%s" # always empty?
-IFIELD IGNORE, "", "%s" # seems to be extra lat/lon values?
+++ /dev/null
-# gpsbabel XCSV style file
-#
-# Format: Kompass / Deutscher Alpenverein (DAV) Waypoints
-# Author: Olaf Klein
-# Date: 01/10/2007
-#
-#
-DESCRIPTION Kompass (DAV) Track (.tk)
-DATATYPE TRACK
-EXTENSION wp
-FIELD_DELIMITER COMMA
-RECORD_DELIMITER NEWLINE
-BADCHARS ,"
-#
-# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE:
-#
-IFIELD LAT_DECIMAL, "", "%.7f"
-IFIELD LON_DECIMAL, "", "%.7f"
+++ /dev/null
-# gpsbabel XCSV style file
-#
-# Format: Kompass / Deutscher Alpenverein (DAV) Waypoints
-# Author: Olaf Klein
-# Date: 01/10/2007
-#
-#
-DESCRIPTION Kompass (DAV) Waypoints (.wp)
-DATATYPE WAYPOINT
-EXTENSION wp
-ENCODING UTF-8
-FIELD_DELIMITER SEMICOLON
-RECORD_DELIMITER CRNEWLINE
-BADCHARS ,"
-#
-# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE:
-#
-IFIELD SHORTNAME, "", "%s"
-IFIELD LON_DECIMAL, "", "%.7f"
-IFIELD LAT_DECIMAL, "", "%.7f"
-IFIELD ALT_METERS, "", "%.0f"
-IFIELD LOCAL_TIME,"","%d.%m.%Y %H:%M:%S"
-IFIELD CONSTANT, "Icons\Wegpunkt grün.bmp", "%s"
-IFIELD IGNORE, "", "%s"
-IFIELD CONSTANT, "1", "%s" # unknown
-IFIELD DESCRIPTION, "", "%s"
+++ /dev/null
-#
-# Support for MainNav CSV format
-#
-# Copyright (C) 2012 Robert Lipe, gpsbabel.org
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# gpsbabel XCSV style file
-# Format: Mainnav MG-950d data logger and possibly others
-# Author: tsteven4
-# Date: December 13, 2012
-#
-#
-DESCRIPTION Mainnav
-EXTENSION nav
-DATATYPE TRACK
-#
-#
-# FILE LAYOUT DEFINITIIONS:
-#
-FIELD_DELIMITER COMMA
-RECORD_DELIMITER NEWLINE
-BADCHARS COMMA
-
-#
-# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE:
-#
-IFIELD LOCAL_TIME, "", "%Y/%m/%d %H:%M:%S"
-IFIELD LON_DECIMAL,"","%.9f"
-IFIELD LON_DIR,"","%c"
-IFIELD LAT_DECIMAL,"","%.9f"
-IFIELD LAT_DIR,"","%c"
-IFIELD ALT_FEET, "", "%f"
-IFIELD IGNORE, "", "%s" # SPD?
-IFIELD IGNORE, "", "%s" # PATH?
-IFIELD IGNORE, "", "%s" # FILENAME?
-IFIELD IGNORE, "", "%s" # MODE?
-IFIELD IGNORE, "", "%s" # JOURNEY_INDEX?
-IFIELD IGNORE, "", "%s" # ?
+++ /dev/null
-# Format: Mapopolis.com Mapconverter
-# Author: Gary Paulson
-# Date: 01/13/2003
-# Requires unsupported mapconverter.exe from mapopolis.com.
-#
-# Modifications by Alex Mottram documented 6/30/2003
-# Change %-40.40s on description output to %-.40s to stop padding.
-# Add QUOTE as badchars, remove COMMA.
-# Removed Mapconverter.exe's README information from style file.
-# Changed OFIELD to IFIELD in case you ever want to read one of these things.
-#
-#
-DESCRIPTION Mapopolis.com Mapconverter CSV
-EXTENSION txt
-
-# FILE LAYOUT DEFINITIIONS:
-
-FIELD_DELIMITER COMMASPACE
-RECORD_DELIMITER NEWLINE
-BADCHARS ",
-
-# Map Info Record (header):
-PROLOGUE M, "Geocaches", "GPSBabel", Geocaches, __FILE__
-#
-
-#
-# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE:
-#
-# L Records:
-IFIELD CONSTANT, "L", "%s" # [L]ANDMARK
-IFIELD CONSTANT, "Geocaches", "%s" # Category for Landmark Searches
-IFIELD DESCRIPTION, "", "%-.40s" # Name
-IFIELD CONSTANT, "1", "%s" # View at Zoom Level 1 (1-4)
-IFIELD LON_DECIMAL, "", "%08.5f" # Longitude
-IFIELD LAT_DECIMAL, "", "%08.5f" # Latitude
+++ /dev/null
-# gpsbabel XCSV style file
-#
-# Format: MOTOACTV CSV
-# Author: Dan Brown
-# Date: 07/21/2012
-#
-# example usage:
-# gpsbabel -i xcsv,style=motoactv.style -f infile.csv -x transform,trk=wpt -o gtrnctr,course=0 -F outfile.tcx
-# gpsbabel -i xcsv,style=motoactv.style -f infile.csv -x transform,trk=wpt -o gpx,garminextensions -F outfile.gpx
-
-DESCRIPTION Motoactiv CSV
-EXTENSION csv
-
-ENCODING US-ASCII
-FIELD_DELIMITER COMMA
-RECORD_DELIMITER NEWLINE
-FIELD_ENCLOSER DOUBLEQUOTE
-
-PROLOGUE "DISTANCE","activity_id","HEARTRATE","SPEED","STEPS_PER_MINUTE","LATITUDE","repetitions","temperature","INSTANT_TORQUE_CRANK","timestamp_epoch","ELEVATION","POWER","STRIDES","wheel_torque","CALORIEBURN","LONGITUDE","CADENCE","heading","STEP_RATE"
-
-# Data fields, in order of appearance
-IFIELD PATH_DISTANCE_METERS,"","%.1f" # used for writing files (not for reading)
-IFIELD IGNORE,"","%s" # activity id
-IFIELD HEART_RATE,"","%d"
-IFIELD PATH_SPEED,"","%.1f"
-IFIELD IGNORE,"","%s" # steps per minute
-IFIELD LAT_DECIMAL,"","%.6f"
-IFIELD IGNORE,"","%s" # repetitions
-IFIELD TEMPERATURE,"","%.1f"
-IFIELD IGNORE,"","%s" # instant torque crank
-IFIELD TIMET_TIME_MS,"","%lld"
-IFIELD ALT_METERS,"","%.1f"
-IFIELD POWER,"","%.0f"
-IFIELD IGNORE,"","%s" # strides
-IFIELD IGNORE,"","%s" # wheel_torque
-IFIELD IGNORE,"","%s" # calories
-IFIELD LON_DECIMAL,"","%.6f"
-IFIELD CADENCE,"","%d"
-IFIELD PATH_COURSE,"","%.1f"
-IFIELD IGNORE,"","%s" # step rate
+++ /dev/null
-# gpsbabel XCSV style file
-#
-# Format: Ozi Explorer
-# Author: Alex Mottram
-# Date: 12/09/2002
-#
-#
-# As used in mxf.c
-#
-#
-
-DESCRIPTION MapTech Exchange Format
-EXTENSION mxf
-
-#
-# FILE LAYOUT DEFINITIIONS:
-#
-FIELD_DELIMITER COMMASPACE
-RECORD_DELIMITER NEWLINE
-BADCHARS ,"
-
-#
-# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE:
-#
-IFIELD LAT_DECIMAL, "", "%08.5f"
-IFIELD LON_DECIMAL, "", "%08.5f"
-IFIELD DESCRIPTION, "", ""%s""
-IFIELD SHORTNAME, "", ""%s""
-IFIELD IGNORE, "", "%s"
-IFIELD CONSTANT, "ff0000", "%s" # COLOR
-IFIELD CONSTANT, "47", "%s" # ICON
-
-OFIELD LAT_DECIMAL, "", "%08.5f"
-OFIELD LON_DECIMAL, "", "%08.5f"
-OFIELD DESCRIPTION, "", ""%s""
-OFIELD SHORTNAME, "", ""%s""
-OFIELD DESCRIPTION, "", ""%s""
-OFIELD CONSTANT, "ff0000", "%s" # COLOR
-OFIELD CONSTANT, "47", "%s" # ICON
+++ /dev/null
-#
-# Map&Guide Motorrad Routenplaner .bcr files test
-#
-rm -f ${TMPDIR}/bcr*
-gpsbabel -r -i bcr -f ${REFERENCE}/route/bcr-sample.bcr -o gpx -F ${TMPDIR}/bcr-sample.gpx
-compare ${REFERENCE}/route/bcr-sample.gpx ${TMPDIR}/bcr-sample.gpx
-gpsbabel -r -i gpx -f ${REFERENCE}/route/bcr-sample.gpx -o bcr -F ${TMPDIR}/bcr-sample2.bcr
-compare ${REFERENCE}/route/bcr-sample2.bcr ${TMPDIR}/bcr-sample2.bcr
-gpsbabel -r -i bcr -f ${TMPDIR}/bcr-sample2.bcr -o gpx -F ${TMPDIR}/bcr-sample2.gpx
-compare ${REFERENCE}/route/bcr-sample.gpx ${TMPDIR}/bcr-sample2.gpx
-
+++ /dev/null
-# F90G Automobile DVR GPS logging
-rm -f ${TMPDIR}/f90g.gpx
-gpsbabel -i f90g -f ${REFERENCE}/track/f90g-sample.map -o gpx -F ${TMPDIR}/f90g.gpx
-compare ${REFERENCE}/track/f90g-sample.gpx ${TMPDIR}/f90g.gpx
+++ /dev/null
-
-#
-# IGN Rando tests
-#
-gpsbabel -i ignrando -f ${REFERENCE}/track/ignrando-sample.rdn -o ignrando -F ${TMPDIR}/ignrando-sample.rdn
-gpsbabel -i ignrando -f ${TMPDIR}/ignrando-sample.rdn -o gpx -F ${TMPDIR}/ignrando-sample.gpx
-compare ${REFERENCE}/track/ignrando-sample.gpx ${TMPDIR}/ignrando-sample.gpx
-
+++ /dev/null
-#
-# igo2008_poi
-#
-gpsbabel -i igo2008_poi -f ${REFERENCE}/igo2008_poi.upoi -o gpx -F ${TMPDIR}/igo2008_poi~upoi.gpx
-compare ${REFERENCE}/igo2008_poi~upoi.gpx ${TMPDIR}/igo2008_poi~upoi.gpx
-gpsbabel -i igo2008_poi -f ${REFERENCE}/igo2008_poi.upoi -o unicsv -F ${TMPDIR}/igo2008_poi~upoi.csv
-compare ${REFERENCE}/igo2008_poi~upoi.csv ${TMPDIR}/igo2008_poi~upoi.csv
-
+++ /dev/null
-# iGo8
-# This format has some jitter in the first 64 bytes of the header.
-# So we read our reference track, spin to GPX.
-# Read that track, spin to igo.
-# read the igo file we just wrote, and spin that to GPX.
-# compare the two GPX files.
-gpsbabel -i igo8 -f ${REFERENCE}/track/igo8.trk -o gpx -F ${TMPDIR}/igo.gpx
-gpsbabel -i gpx -f ${TMPDIR}/igo.gpx -o igo8 -F ${TMPDIR}/new-igo.trk
-gpsbabel -i igo8 -f ${TMPDIR}/new-igo.trk -o gpx -F ${TMPDIR}/new-igo2.gpx
-compare ${TMPDIR}/igo.gpx ${TMPDIR}/new-igo2.gpx
-# On 6/23/10, we received reports of IGO files that were trailing padded.
-# verify that one such files converts sensibly to GPX.
-
-gpsbabel -i igo8 -f ${REFERENCE}/track/igo8_padded.trk -o gpx -F ${TMPDIR}/igo8_padded.gpx
-compare ${REFERENCE}/track/igo8_padded~gpx.gpx ${TMPDIR}/igo8_padded.gpx
-
-# test header.
-gpsbabel -i igo8 -f ${REFERENCE}/track/igo8.trk -o igo8,title="Track 001",description="recorded track log",tracknum=3 -F ${TMPDIR}/igo8.trk
-bincompare ${REFERENCE}/track/igo8.trk ${TMPDIR}/igo8.trk
+++ /dev/null
-#
-# igoprimo_poi
-#
-gpsbabel -i igoprimo_poi -f ${REFERENCE}/igoprimo_poi.upoi -o gpx -F ${TMPDIR}/igoprimo_poi~upoi.gpx
-compare ${REFERENCE}/igoprimo_poi~upoi.gpx ${TMPDIR}/igoprimo_poi~upoi.gpx
-gpsbabel -i igoprimo_poi -f ${REFERENCE}/igoprimo_poi.upoi -o unicsv -F ${TMPDIR}/igoprimo_poi~upoi.ucsv
-compare ${REFERENCE}/igoprimo_poi~upoi.ucsv ${TMPDIR}/igoprimo_poi~upoi.ucsv
-
-gpsbabel -i igoprimo_poi -f ${REFERENCE}/igoprimo_poi.upoi -o igoprimo_poi -F ${TMPDIR}/igoprimo_poi~upoi.upoi
-iconv -f UTF-16LE -t UTF-8 ${REFERENCE}/igoprimo_poi.upoi >${TMPDIR}/igoprimo_poi.upoi.utf8
-iconv -f UTF-16LE -t UTF-8 ${TMPDIR}/igoprimo_poi~upoi.upoi >${TMPDIR}/igoprimo_poi~upoi.upoi.utf8
-compare ${TMPDIR}/igoprimo_poi~upoi.upoi.utf8 ${TMPDIR}/igoprimo_poi~upoi.upoi.utf8
\ No newline at end of file
+++ /dev/null
-#
-# MagicMaps IK3D Project File .ikt test
-#
-gpsbabel -i ik3d -f ${REFERENCE}/ik3d-sample.ikt -o gpx -F ${TMPDIR}/ik3d-sample.gpx
-compare ${REFERENCE}/ik3d-sample.gpx ${TMPDIR}/ik3d-sample.gpx
-
+++ /dev/null
-
-#
-# Nokia LMX
-#
-gpsbabel -i lmx -f ${REFERENCE}/nokia.lmx -o lmx -F ${TMPDIR}/nokia.lmx
-compare ${REFERENCE}/nokia.lmx ${TMPDIR}/nokia.lmx
-gpsbabel -i lmx -f ${REFERENCE}/nokia.lmx -o lmx,binary -F ${TMPDIR}/binary.lmx
-bincompare ${REFERENCE}/binary.lmx ${TMPDIR}/binary.lmx
-
+++ /dev/null
-#!/bin/sh
-
-#
-# Mainnav tests
-#
-gpsbabel -i mainnav -f ${REFERENCE}/track/mainnav_mg-950d.nav -o gpx -F ${TMPDIR}/mainnav_mg-950d.gpx
-compare ${REFERENCE}/track/mainnav_mg-950d.gpx ${TMPDIR}/mainnav_mg-950d.gpx
-
+++ /dev/null
-#
-# MapAsia tr7 tracks
-#
-gpsbabel -i mapasia_tr7 -f ${REFERENCE}/track/mapasia-tr7.tr7 -t -o unicsv,utc=0 -F ${TMPDIR}/mapasia~tr7.csv
-compare ${REFERENCE}/track/mapasia~tr7.csv ${TMPDIR}/mapasia~tr7.csv
-gpsbabel -i mapasia_tr7 -f ${REFERENCE}/track/mapasia-tr7.tr7 -o gpx -F ${TMPDIR}/mapasia~tr7.gpx
-compare ${REFERENCE}/track/mapasia~tr7.gpx ${TMPDIR}/mapasia~tr7.gpx
-
+++ /dev/null
-# Mapbar/Sonim XP330
-rm -f ${TMPDIR}/mapbar.gpx
-gpsbabel -i mapbar -f ${REFERENCE}/track/mapbar.trk -o gpx -F ${TMPDIR}/mapbar.gpx
-compare ${REFERENCE}/track/mapbar~gpx.gpx ${TMPDIR}/mapbar.gpx
+++ /dev/null
-#
-# Mapfactor Navigator
-#
-
-gpsbabel -i mapfactor -f ${REFERENCE}/mapfactor.xml -o gpx -F ${TMPDIR}/mapfactor.gpx -o mapfactor -F ${TMPDIR}/mapfactor.xml
-compare ${REFERENCE}/mapfactor~gpx.gpx ${TMPDIR}/mapfactor.gpx
-compare ${REFERENCE}/mapfactor.xml ${TMPDIR}/mapfactor.xml
+++ /dev/null
-#
-# Memory-Map Navigator overlay files (.mmo)
-#
-# reading version 22 (0x16)
-gpsbabel -i mmo -f ${REFERENCE}/memory-map.mmo -o gpx -F ${TMPDIR}/memory-map~mmo.gpx
-compare ${REFERENCE}/memory-map~mmo.gpx ${TMPDIR}/memory-map~mmo.gpx
-# reading version 24 (0x18)
-gpsbabel -i mmo -f ${REFERENCE}/memory-map_v24.mmo -o gpx -F ${TMPDIR}/memory-map_v24~mmo.gpx
-compare ${REFERENCE}/memory-map_v24~mmo.gpx ${TMPDIR}/memory-map_v24~mmo.gpx
-# writing (check only for memory leaks)
-gpsbabel -i gpx -f ${REFERENCE}/memory-map~mmo.gpx -o mmo -F ${TMPDIR}/memory-map~mmo.mmo
-gpsbabel -i mmo -f ${TMPDIR}/memory-map~mmo.mmo -o gpx -F ${TMPDIR}/memory-map~mmo~gpx.mmo
-
-# we can only write version 17 (0x11) or 18 (0x12).
-# we don't have a reference file from these versions, so we will create one and
-# see if we can write it out without change.
-gpsbabel -i mmo -f ${REFERENCE}/memory-map.mmo -o mmo -F ${TMPDIR}/memory-map.mmo
-gpsbabel -i mmo -f ${TMPDIR}/memory-map.mmo -o mmo -F ${TMPDIR}/memory-map~mmo.mmo
-bincompare ${TMPDIR}/memory-map.mmo ${TMPDIR}/memory-map~mmo.mmo
+++ /dev/null
-
-rm -f ${TMPDIR}/motoactv.*
-gpsbabel -i motoactv -f ${REFERENCE}/track/motoactv.csv -o gpx -F ${TMPDIR}/motoactv~csv.gpx
-compare ${REFERENCE}/track/motoactv~gpx.gpx ${TMPDIR}/motoactv~csv.gpx
-
-
+++ /dev/null
-
-# MXF (Maptech Exchange Format) file format
-rm -f ${TMPDIR}/mx.mxf ${TMPDIR}/mxf.mxf
-gpsbabel -i mxf -f ${REFERENCE}/mxf.mxf -o mxf -F ${TMPDIR}/mx.mxf
-gpsbabel -i mxf -f ${TMPDIR}/mx.mxf -o mxf -F ${TMPDIR}/mxf.mxf
-compare ${TMPDIR}/mxf.mxf ${REFERENCE}
-
+++ /dev/null
-#
-# Basic mynav tests (readonly)
-#
-rm -f ${TMPDIR}/mynav*
-gpsbabel -i mynav -f ${REFERENCE}/track/mynav.trc -o gpx,garminextensions -F ${TMPDIR}/mynav1.gpx
-compare ${REFERENCE}/track/mynav1.gpx ${TMPDIR}/mynav1.gpx
-gpsbabel -i mynav -f ${REFERENCE}/track/mynav.ftn -o gpx,garminextensions -F ${TMPDIR}/mynav2.gpx
-compare ${REFERENCE}/track/mynav2.gpx ${TMPDIR}/mynav2.gpx
+++ /dev/null
-#
-# tef "TourExchangeFormat" read test
-#
-rm -f ${TMPDIR}/tef_xml*
-gpsbabel -i tef -f ${REFERENCE}/route/tef_xml.sample.xml -o gpx -F ${TMPDIR}/tef_xml.sample.gpx
-compare ${REFERENCE}/route/tef_xml.sample.gpx ${TMPDIR}/tef_xml.sample.gpx
-
#include "dg-100.h" // for Dg100FileFormat, Dg100SerialFormat, Dg200FileFormat, Dg200SerialFormat
#include "energympro.h" // for EnergymproFormat
#include "exif.h" // for ExifFormat
-#include "f90g_track.h" // for F90gTrackFormat
#include "format.h" // for Format
#include "garmin_fit.h" // for GarminFitFormat
#include "garmin_gpi.h" // for GarminGPIFormat
#include "kml.h" // for KmlFormat
#include "legacyformat.h" // for LegacyFormat
#include "lowranceusr.h" // for LowranceusrFormat
-#include "mapbar_track.h" // for MapbarTrackFormat
-#include "mapfactor.h" // for MapfactorFormat
-#include "mynav.h" // for MyNavFormat
#include "nmea.h" // for NmeaFormat
#include "osm.h" // for OsmFormat
#include "qstarz_bl_1000.h" // for QstarzBL1000Format
#include "skytraq.h" // for MinihomerFormat, SkytraqFormat, SkytraqfileFormat
#include "src/core/logging.h" // for Warning, FatalMsg
#include "subrip.h" // for SubripFormat
-#include "tef_xml.h" // for TefXMLFormat
#include "teletype.h" // for TeletypeFormat
#include "text.h" // for TextFormat
#include "unicsv.h" // for UnicsvFormat
extern ff_vecs_t mtk_fvecs;
extern ff_vecs_t mtk_m241_vecs;
extern ff_vecs_t mtk_m241_fvecs;
-extern ff_vecs_t mtk_locus_vecs;
#endif // MAXIMAL_ENABLED
extern ff_vecs_t wbt_svecs;
#if MAXIMAL_ENABLED
extern ff_vecs_t vcf_vecs;
extern ff_vecs_t google_dir_vecs;
extern ff_vecs_t tomtom_vecs;
-extern ff_vecs_t bcr_vecs;
-extern ff_vecs_t ignr_vecs;
extern ff_vecs_t gtm_vecs;
extern ff_vecs_t gpssim_vecs;
#if CSVFMTS_ENABLED
extern ff_vecs_t dmtlog_vecs;
extern ff_vecs_t raymarine_vecs;
extern ff_vecs_t ggv_log_vecs;
-extern ff_vecs_t lmx_vecs;
extern ff_vecs_t xol_vecs;
extern ff_vecs_t navilink_vecs;
-extern ff_vecs_t ik3d_vecs;
extern ff_vecs_t destinator_poi_vecs;
extern ff_vecs_t destinator_itn_vecs;
extern ff_vecs_t destinator_trl_vecs;
-extern ff_vecs_t igo8_vecs;
-extern ff_vecs_t mapasia_tr7_vecs;
extern ff_vecs_t gnav_trl_vecs;
extern ff_vecs_t navitel_trk_vecs;
extern ff_vecs_t ggv_ovl_vecs;
extern ff_vecs_t itracku_fvecs;
extern ff_vecs_t sbp_vecs;
extern ff_vecs_t sbn_vecs;
-extern ff_vecs_t mmo_vecs;
extern ff_vecs_t v900_vecs;
extern ff_vecs_t enigma_vecs;
extern ff_vecs_t format_garmin_xt_vecs;
LegacyFormat mtk_ffmt {mtk_fvecs};
LegacyFormat mtk_m241_fmt {mtk_m241_vecs};
LegacyFormat mtk_m241_ffmt {mtk_m241_fvecs};
- LegacyFormat mtk_locus_fmt {mtk_locus_vecs};
#endif // MAXIMAL_ENABLED
LegacyFormat wbt_sfmt {wbt_svecs};
#if MAXIMAL_ENABLED
LegacyFormat vcf_fmt {vcf_vecs};
LegacyFormat google_dir_fmt {google_dir_vecs};
LegacyFormat tomtom_fmt {tomtom_vecs};
- TefXMLFormat tef_xml_fmt;
- LegacyFormat bcr_fmt {bcr_vecs};
- LegacyFormat ignr_fmt {ignr_vecs};
UnicsvFormat unicsv_fmt;
LegacyFormat gtm_fmt {gtm_vecs};
LegacyFormat gpssim_fmt {gpssim_vecs};
LegacyFormat raymarine_fmt {raymarine_vecs};
LegacyFormat ggv_log_fmt {ggv_log_vecs};
GarminGPIFormat garmin_gpi_fmt;
- LegacyFormat lmx_fmt {lmx_vecs};
RandomFormat random_fmt;
LegacyFormat xol_fmt {xol_vecs};
Dg100SerialFormat dg100_fmt;
Dg200SerialFormat dg200_fmt;
Dg200FileFormat dg200_ffmt;
LegacyFormat navilink_fmt {navilink_vecs};
- LegacyFormat ik3d_fmt {ik3d_vecs};
OsmFormat osm_fmt;
LegacyFormat destinator_poi_fmt {destinator_poi_vecs};
LegacyFormat destinator_itn_fmt {destinator_itn_vecs};
LegacyFormat destinator_trl_fmt {destinator_trl_vecs};
ExifFormat exif_fmt;
- LegacyFormat igo8_fmt {igo8_vecs};
HumminbirdFormat humminbird_fmt;
HumminbirdHTFormat humminbird_ht_fmt;
- LegacyFormat mapasia_tr7_fmt {mapasia_tr7_vecs};
LegacyFormat gnav_trl_fmt {gnav_trl_vecs};
LegacyFormat navitel_trk_fmt {navitel_trk_vecs};
LegacyFormat ggv_ovl_fmt {ggv_ovl_vecs};
LegacyFormat itracku_ffmt {itracku_fvecs};
LegacyFormat sbp_fmt {sbp_vecs};
LegacyFormat sbn_fmt {sbn_vecs};
- LegacyFormat mmo_fmt {mmo_vecs};
LegacyFormat v900_fmt {v900_vecs};
LegacyFormat enigma_fmt {enigma_vecs};
SkytraqFormat skytraq_fmt;
SubripFormat subrip_fmt;
LegacyFormat format_garmin_xt_fmt {format_garmin_xt_vecs};
GarminFitFormat format_fit_fmt;
- MapbarTrackFormat mapbar_track_fmt;
- F90gTrackFormat f90g_track_fmt;
- MapfactorFormat mapfactor_fmt;
EnergymproFormat energympro_fmt;
- MyNavFormat mynav_fmt;
GeoJsonFormat geojson_fmt;
GgvBinFormat ggv_bin_fmt;
GlobalsatSportFormat globalsat_sport_fmt;
"bin",
nullptr,
},
- {
- &mtk_locus_fmt,
- "mtk_locus",
- "MediaTek Locus",
- nullptr,
- nullptr,
- },
#endif // MAXIMAL_ENABLED
{
&wbt_sfmt,
"ov2",
nullptr,
},
- {
- &tef_xml_fmt,
- "tef",
- "Map&Guide 'TourExchangeFormat' XML",
- "xml",
- nullptr,
- },
- {
- &bcr_fmt,
- "bcr",
- "Motorrad Routenplaner (Map&Guide) .bcr files",
- "bcr",
- nullptr,
- },
- {
- &ignr_fmt,
- "ignrando",
- "IGN Rando track files",
- "rdn",
- nullptr,
- },
{
&unicsv_fmt,
"unicsv",
"gpi",
nullptr,
},
- {
- &lmx_fmt,
- "lmx",
- "Nokia Landmark Exchange",
- nullptr,
- nullptr,
- },
{
&random_fmt,
"random",
nullptr,
nullptr,
},
- {
- &ik3d_fmt,
- "ik3d",
- "MagicMaps IK3D project file (.ikt)",
- "ikt",
- nullptr,
- },
{
&osm_fmt,
"osm",
"jpg",
nullptr,
},
- {
- &igo8_fmt,
- "igo8",
- "IGO8 .trk",
- "trk",
- nullptr,
- },
{
&humminbird_fmt,
"humminbird",
"ht",
nullptr,
},
- {
- &mapasia_tr7_fmt,
- "mapasia_tr7",
- "MapAsia track file (.tr7)",
- "tr7",
- nullptr,
- },
{
&gnav_trl_fmt,
"gnav_trl",
"sbn",
nullptr,
},
- {
- &mmo_fmt,
- "mmo",
- "Memory-Map Navigator overlay files (.mmo)",
- "mmo",
- nullptr,
- },
{
&v900_fmt,
"v900",
"fit",
nullptr,
},
- {
- &mapbar_track_fmt,
- "mapbar",
- "Mapbar (China) navigation track for Sonim Xp3300",
- "trk",
- nullptr,
- },
- {
- &f90g_track_fmt,
- "f90g",
- "F90G Automobile DVR GPS log file",
- "map",
- nullptr,
- },
- {
- &mapfactor_fmt,
- "mapfactor",
- "Mapfactor Navigator",
- "xml",
- nullptr,
- },
{
&energympro_fmt,
"energympro",
"cpo",
nullptr,
},
- {
- &mynav_fmt,
- "mynav",
- "MyNav TRC format",
- "trc",
- nullptr,
- },
{
&geojson_fmt,
"geojson",
+++ /dev/null
-<para>
-This file format (extension .bcr) is used in Map&Guide
-<productname>Motorrad Routenplaner 2002</productname> and later versions.
-BCR is a route-only format. If you own a newer release (2005 or later) you
-may also use the XML export with GPSBabel's <link linkend="fmt_tef">tef</link>
-input format.
-</para>
-<para>
-There may be other products from Map&Guide that use this format as well.
-</para>
-<para>
-Coordinates are stored in a BCR file in a Mercator projection. The
-conversion from the Mercator projection to polar (latitude/longitude)
-coordinates and back again may result in visible differences. Experience
-reports are welcome.
-</para>
-<example id="sample_bcr_command">
- <title>Sample BCR command with all options</title>
- <para><userinput>gpsbabel -r -i gpx -f in.gpx -o bcr,index=1,name="From A to B",radius=6371012 -F a_to_b.bcr</userinput></para>
-</example>
-
+++ /dev/null
-<para>
-
-This format is for the .map files produced by the F90G automobile
-Digital Video Recorder (DVR) when recording videos. The files are
-found on the sd card in /DCIM/DCIMA/NORMAL/ and are named with a time
-stamp and the .map extension. This format records each track point's
-latitude, longitude, local time, GMT time and velocity in Kilometers
-Per Hour. The local time is used in the gpsbabel translation.
-Minutes, seconds and the velocity are combined to form each track point's
-name in the converted trace.
-</para>
-<para>
-This was implemented by analyzing data from a F90G DVR supplied from China.
-Firmware F20-2013121217-E
-</para>
-<para>
-The format was tested only using .map samples collected in the USA. We are
-interested in samples or test results from other hemispheres.
-</para>
+++ /dev/null
-<para>
-This format supports IGN Rando track files. IGN Rando is a program mainly
-used in France for Topo maps. The files are XML based and are "windows-1252"
-encoded. Trackpoints do not have time stamps.
-</para>
-
+++ /dev/null
-<para>
- igo2008_poi supports POI files from <productname>Nav N Go iGO 8 Europe</productname>.
- This is a GPS Navigation Software for <productname>Windows Mobile</productname> based
- PDA devices and Smartphones.
-</para>
+++ /dev/null
-<para>
- iGo8 is the successor to the "iGo My way" software package that is reasonably
- prolific for GPS devices manufactured by Mio, Sony, LG, as well as many other
- small manufacturers. iGo8 is notable in that it has full 3D rendering of
- terrain as well as buildings and landmarks for most large cities. The
- software can also be bought pre-loaded on a mico-SD card for use in many PPC
- phones that are GPS enabled.
-</para>
-
-<para>
- The track format used by iGo8 is rather rudimentary, consisting of a list of
- coordinates and a time resolution of 1 second. While iGo8 supports exporting
- tracks to GPX format, importing tracks is not natively supported.
-</para>
+++ /dev/null
-<para>
- igoprimo_poi supports POI files from <productname>iGo Primo</productname> 'next generation
- navigation' devices. iGo Primo is GPS Navigation Software that runs on Windows embedded
- platforms, and is used in some OEM and aftermarket automotive head units.
-</para>
+++ /dev/null
-<para>
- This is the format for <ulink url="http://www.magicmaps.de">MagicMaps</ulink> project (.ikt) files.
-</para>
-<para>
- <ulink url="http://www.magicmaps.de">MagicMaps</ulink> <productname>"Das interaktive Kartenwerk"</productname> is a Software from Germany. It's a
- route-planning software with a 3-dimensional environment.
-</para>
-<para>
- The project files are XML based and we can read the main GPS items (names and coordinates).
- For an output these files are too complex.
-</para>
+++ /dev/null
-<para>
- This module supports track files used by Kompass and DAV "Deutscher Alpenverein".
-</para>
-<para>
- <ulink url="http://www.kompass.at">Kompass</ulink> is a publishing company from Austria.
- If you want to get more information about DAV, the German alpine association,
- and if you are familiar with the german language, please have a look at their <ulink url="http://www.alpenverein.de">homepage</ulink>.
-</para>
+++ /dev/null
-<para>
- This module supports waypoint files used by Kompass and DAV "Deutscher Alpenverein".
-</para>
-<para>
- Some more information under <link linkend="fmt_kompass_tk">kompass_tk</link> format.
-</para>
-
+++ /dev/null
-<para>
-This format supports
-<ulink url="http://sw.nokia.com/id/9001c8de-c19e-41a0-87d3-5be4297e4d4c/S60_Platform_Landmarks_Exchange_Specification_v1_0_en.pdf">
-Nokia Landmark Exchange (LMX) files</ulink> used by several Nokia phones.
-GPSBabel supports the traditional XML format for reading and writing. The
-compressed binary format (WBXML) can be written, but most current Nokia phones
-do not support it (confirmed with N82 and N95).
-</para>
-<para>
-With this format, landmarks can be imported into the landmark store of the
-mobile phone. This landmark store is then used to display them on a map with
-several applications. The most common ones are the pre-installed Ovi Maps (or
-its predecessor Nokia Maps) and Google Maps Mobile.
-</para>
+++ /dev/null
-<para>
-This is the format used by the <ulink url="http://www.mainnav.com">Mainnav</ulink> MG-950d data logger. It may work with other Mainnav devices.
-</para>
+++ /dev/null
-<para>
- This format is the Mapbar navigation programs used on phones such as
- the Sonim XP3300 popular in China.
- The files are found on the sd card in /mapbar/userdata/tracks.
- This format just logs track point by latitude and longitude; no time
- information is available.
-</para>
-<para>
-This was implemented by analyzing data from a Sonin SoninXp3300,
-software version: 3.73.47.39836, data version: B29.
-</para>
-<para>
-The following devices of using mapbar navigation are supported. Other
-devices with using mapbar navigation maybe be supported, but not have
-not been tested:
-<simplelist columns="1">
-<member>Sonim Xp3300(China version)</member>
-</simplelist>
-</para>
+++ /dev/null
-<para>
-Mapconverter is a format that is read by Mapopolis.com's
-mapconverter application.
-</para>
-<para>
-Mapconverter is an application used to create userland maps and map data for
-Mapopolis.com's Mapopolis program. The mapconverter format is essentially
-waypoint data prepared in a format that the mapconverter application will
-accept.
-</para>
-<para>
-The steps for using GPSBabel and Mapconverter go something like this:
-</para>
-<para>
-Step 1: Create a mapconverter file using gpsbabel.
-</para>
-<para><userinput>gpsbabel -i geo -f geocaching.loc -o mapconverter -F foo.txt</userinput></para>
-<para>
-Step 2: Launch mapconverter.exe and choose foo.txt as your input file.
- Click the begin button to have mapconverter process foo.txt.
-</para>
-<para>
-If all goes successfully, you should have a file called "foo.pdb" ready
-for syncing with your PDA. Put it wherever Mapopolis thinks it should be
-on your PDA.
-</para>
-<section id="fmt_mapconverter_notes">
-<title>Notes</title>
-<itemizedlist>
-<listitem>
-<para>
-GPSBabel will write the name of its own output file in the output file
- it creates as the input for Mapconverter. Mapconverter will replace
- the extension of this filename with ".pdb".
-</para>
-</listitem>
-<listitem>
-<para>
-The PocketPC version of Mapopolis doesn't notice files with the ".pdb"
- extension. To make this work, change the extension to ".mlp" when
- copying the mapconverter output to your PocketPC PDA.
-</para>
-</listitem>
-<listitem>
-<para>
-Mapconverter only works with Mapopolis version 3.x. Mapopolis version
- 4 will refuse to load mapconverter maps. There is no known work-around
- for this at the time of this writing.
-</para>
-</listitem>
-<listitem>
-<para>
-Mapconverter is no longer available from the Mapopolis website. If you
- need a copy of mapconverter, ask on your local GPS Software discussion
- forum and I'm sure someone will have it. As far as I know, It was never
- actually acknowledged/supported by Mapopolis to begin with.
-</para>
-</listitem>
-</itemizedlist>
-</section>
-
+++ /dev/null
-<para>
-This format can write a favourites.xml file that stores the waypoints in the Mapfactor Navigator street navigation program for Windows and Android OS. The waypoints are listed in the My places menu option. The favourites.xml file are stored in the Navigator directory.
-</para>
-
-<para>
-This format can read waypoints from the favourites.xml file to use in other programs.
-</para>
-
-
-<para>
-The format has been tested with Windows 8, Navigator version 12.3 and Android OS, v4.2.2, Navigator version 1.1.5.
-</para>
-
-<para>
-The format has been tested with Windows 8, Navigator version 12.3 and Android OS, v4.2.2, Navigator version 1.1.5.
-</para>
-
-<para>
-Groups are not supported, as they don't map well to other more common
-file formats.
-</para>
-
-
+++ /dev/null
-<para>
- The 'mmo' format provides support for binary .mmo files used by the
- Memory-Map Navigator software.
-</para>
-<para>
- Our module was reverse engineered from a couple of .mmo files found
- in the www. The results of the writing code have been tested with a current
- Memory-Map Navigator trial ('Viewer') release.
-</para>
-<para>
- Because of different file versions and sometimes slightly different file structure
- we cannot ensure, that every .mmo file is loadable at this time. If you have one,
- which causes errors, please provide it [mailto:gpsbabel-misc@lists.sourceforge.net].
-</para>
-<para>
- More information can be found at the
- <ulink url="http://www.memory-map.com/">Memory-Map</ulink> site.
-</para>
+++ /dev/null
-<para>
-The <productname>MotoACTV</productname> smart watch creates csv
-format files. GPSBabel can read and write these files through
-the xcsv format when using the included motoactv.style specification.
-</para>
-<para>
-The specific format of the csv file has changed over time, to
-add new data fields. The current version of the GPSBabel style
-specification expects to work with this ordered set of fields:
-</para>
-<para>
-"DISTANCE","activity_id","HEARTRATE","SPEED","STEPS_PER_MINUTE",
-"LATITUDE","repetitions","temperature","INSTANT_TORQUE_CRANK",
-"timestamp_epoch","ELEVATION","POWER","STRIDES","wheel_torque",
-"CALORIEBURN","LONGITUDE","CADENCE","heading","STEP_RATE"
-</para>
-<para><userinput>
-gpsbabel -i motoactv -f rawDataCsv.csv
--x transform,trk=wpt -o gtrnctr,course=0 -F outfile.tcx
-</userinput></para>
+++ /dev/null
-<para>
-This format is a protocol supports the MediaTek MT3339, a GPS
-chipset that shipped around 2011 that has internal logging capability.
-It is the
-core of at least two GPS modules, including the
-GlobalTop PA6H and the Fastrax IT530. The GlobalTop PA6H module is in
-turn the heart of the Adafruit "Ultimate" GPS breakout board, popular
-in the Arduino "maker" world.
-</para>
-<para>
-It is similar to the mtk and mtk-bin formats for earlier Mediatek parts.
-</para>
+++ /dev/null
-
-
-
- <para>Maptech Exchange Format - Another CSV format file. This
-format complies with (at least) Maptech Terrain Navigator, Terrain
-Professional, Take a Hike, and ExpertGPS import/export MFX.
-Contributed by Alex Mottram.</para>
-
+++ /dev/null
-<para>
- Input support for the TRC file format used by <productname>MyNav Map
- Manager</productname> and <productname>VDO GP7</productname> GPS
- devices.
-</para>
-<para>
- For information on the data format see <ulink
- url="http://www.mynav.it/hwdoc/dev/TRC_Format_Spec.pdf">track format
- specification</ulink>.
-</para>
-<para>
- <userinput>
- gpsbabel -i mynav -f infile.trc -o gpx,garminextensions -F outfile.gpx
- </userinput>
-</para>
+++ /dev/null
-<para>
-TEF, internally called "TourExchangeFormat", is an XML based export format
-used by Map&Guide <productname>Motorrad-Routenplaner 2005/06</productname>.
-</para>
-<para>
-Because this is only an export format, GPSBabel does not support writing to
-this format.
-</para>
-<para>
-GPSBabel also supports the <link linkend="fmt_bcr">bcr</link> format, which
-may also be used with this program and supports both reading and writing.
-</para>
-
-<para><userinput> gpsbabel -r -i tef,routevia -f in.xml -o gpx -F out.gpx</userinput></para>
-